模拟Secretary problem(秘书问题)结果异常,期望37%却仅得约10%
秘书问题模拟错误分析与修正
核心错误:统计目标完全偏离秘书问题定义
秘书问题的核心是计算选中全局最优候选人(即分数最大值)的概率,但你的代码一直在累加选中者的分数平均值——这完全是两个不同的指标。你现在找的是“能拿到最高平均分数”的策略,而非“选中最优者概率最高”的策略,这就是结果和1/e(约37%)完全不匹配的根本原因。
代码中的具体问题
- 统计逻辑完全错误:你应该统计「每次试验中,当前策略是否选中了全局最大值」,而非累加选中者的分数。比如每次试验先记录全局最大值,再判断按策略选中的是否为该值,是则计数+1,最终用
计数/试验次数得到该策略的成功率。 - 变量命名误导:
let min=Math.max(...x.splice(0,i));里的min完全是错误命名,应该叫maxRejected或bestInFirstI,虽然不影响运行,但会干扰问题排查。 select!=0判断有漏洞:如果前i个的最大值是0.8,剩下的候选人分数都低于0.8,select会保持0,此时你加的是最后一个人的分数,但这种情况策略根本没选中全局最大值,你的统计方式完全没记录这个关键信息。
修正后的代码
// 候选人数量 const people = 100; // 试验次数,建议增加到10000以获得更稳定的结果 const trials = 10000; // 记录每个策略(拒绝前i个)选中最优者的次数 const successCounts = new Array(people).fill(0); for (let i = 0; i < people; i++) { for (let j = 0; j < trials; j++) { // 生成随机分数数组,每个候选人分数为0-1的独立随机数 const scores = Array.from({ length: people }, () => Math.random()); // 获取全局最大值 const globalMax = Math.max(...scores); // 计算前i个候选人中的最高分 let maxRejected = -Infinity; if (i > 0) { maxRejected = Math.max(...scores.slice(0, i)); } // 执行策略:从第i+1个开始,选第一个比maxRejected高的候选人 let selectedScore = null; for (let k = i; k < people; k++) { if (scores[k] >= maxRejected) { selectedScore = scores[k]; break; } } // 若后续无人达标,选最后一个候选人 if (selectedScore === null) { selectedScore = scores[people - 1]; } // 判断是否选中全局最大值,是则计数+1 if (selectedScore === globalMax) { successCounts[i]++; } } } // 计算每个策略的成功率 const successRates = successCounts.map(count => count / trials); // 找到成功率最高的策略对应的拒绝比例 const bestIndex = successRates.indexOf(Math.max(...successRates)); const bestPercentage = (bestIndex / people * 100).toFixed(2); console.log(`最优策略:拒绝前 ${bestPercentage}% 的候选人,成功率约 ${(Math.max(...successRates)*100).toFixed(2)}%`);
额外说明
你怀疑的let x=new Array(people).fill(0).map(e=>Math.random())这行代码是没问题的:fill(0)后用map生成每个独立的随机数,每个元素都是不同的随机值,完全符合模拟需求。
内容的提问来源于stack exchange,提问作者Anonymous Camel
相关产品推荐
相关产品推荐

