图 1:本文封面,四步倒推链的答案在最后一环。
先说明属性:这是一篇经典题解析,题目出自本地历史面试资料,与任何公司的当前招聘无关。「5 个人分 100 枚金币」是博弈论逆向归纳的招牌题,很多人背过答案却讲不清过程,面试官要的恰恰是那条倒推链。
先把规则钉死,差一个字答案就变。
5 个人按等级 A、B、C、D、E 依次提案分配 100 枚金币。规则:提案被过半否决,提案者扔下海,由下一人接着提案;否决未过半——包括恰好一半人反对——提案通过。还有三个隐含假设:人人绝对理性,只为最大化自己的收益;收益相同时宁可投反对(看别人下海不花自己一分钱);所有人都知道别人也这么想。正是「平票算通过」这一条,决定了后面每一步的票价,答题前务必先和面试官确认。
从终点倒推:先算只剩两个人的残局。
正向思考「A 该给谁分多少」会想晕,逆向归纳的做法是先站到游戏终点,再一层层往回走。
最小残局是只剩 D、E 两人。D 提案,自己投一张赞成票;E 就算反对,反对票也只有 1 张,恰好半数、未过半,提案照样通过。所以 D 独吞 100,E 得 0——这是整条推理链的地基。
每加一个人,重算一次「下轮所得」。
C 加入后剩三人。过半否决需要 2 张反对票,所以 C 自己赞成之外,只需再买 1 张票。买谁?看谁下一轮拿得最少:残局里 E 得 0,给 1 枚就比下轮强;D 下轮独吞 100,根本买不起。于是方案是 C=99、D=0、E=1,反对票只有 D 一张,提案通过。
B 加入后剩四人。过半否决需要 3 张反对票,B 自己赞成后再买 1 张票就够。上一轮的分配是 C=99、D=0、E=1,最便宜的是拿 0 的 D,给 1 枚收买。方案 B=99、C=0、D=1、E=0,C 和 E 反对也只有 2 票,恰好半数,提案照过。
回到全局:A 的最优解。
A 提案时 5 人投票,过半否决需要 3 张反对票,A 自己赞成后再买 2 张票即可。上一轮 B 的方案里,C 和 E 都得 0,正好是全场最便宜的两张票,各给 1 枚。最终方案:A=98、B=0、C=1、D=0、E=1。反对票只有 B 和 D 两张,提案通过——先手 A 用 2 枚金币买下关键票,自己留下 98 枚。
注意一个常见误答是 A 留 97:那是把「买下两票」的账算错了。98+1+1 正好 100,每一枚都对得上。
用代码把每一步验证一遍。
下面这段程序把倒推过程一般化:从 1 人残局开始,每加一人就按「否决不超过半数」算出需要收买的票数,再从便宜到贵买下「下一轮拿得最少」的人。用 Node.js 22.15.0 运行(node pirates.js):
function solve(n, total = 100) {
let dp = [[total]]; // 只剩 1 人:独吞
for (let k = 2; k <= n; k++) {
const prev = dp[k - 2]; // 剩 k-1 人时的分配
const maxAgainst = Math.floor(k / 2); // 否决数须 <= floor(k/2)
const buyCount = k - maxAgainst - 1; // 扣掉提案者自己的赞成票
// 收买成本 = 此人下一轮所得 + 1,从便宜到贵排序
const cost = prev.map(v => v + 1)
.map((c, i) => [c, i]).sort((a, b) => a[0] - b[0]);
const alloc = new Array(k).fill(0);
let spent = 0;
for (let t = 0; t < buyCount; t++) {
alloc[cost[t][1] + 1] = cost[t][0];
spent += cost[t][0];
}
alloc[0] = total - spent;
dp.push(alloc);
}
return dp;
}
const names = ['A', 'B', 'C', 'D', 'E'];
for (const [i, alloc] of solve(5).entries()) {
const people = names.slice(5 - (i + 1));
console.log(`剩 ${i + 1} 人(${people.join('、')}):` +
alloc.map((v, j) => `${people[j]}=${v}`).join(' '));
}
实测输出:
剩 1 人(E):E=100
剩 2 人(D、E):D=100 E=0
剩 3 人(C、D、E):C=99 D=0 E=1
剩 4 人(B、C、D、E):B=99 C=0 D=1 E=0
剩 5 人(A、B、C、D、E):A=98 B=0 C=1 D=0 E=1
输出与手工倒推逐行吻合,最后一行就是答案。
图 2:分配矩阵逐行展示了从 2 人残局到 5 人全局的倒推过程。
这道题真正的考点是推理方向。
题目本身半小时能背完,但它示范的「从终点倒推每一步最优」是策略推演的通用范式:多智能体协商里先算谈判破裂时各方的保底收益,再决定当下让步多少;拍卖机制设计里先算最后一轮的均衡出价,再反推首轮报价。看懂倒推,就看懂了这一类机制设计题的共同骨架。
回到面试现场,建议的答题结构:先确认规则细节(平票算不算通过、无差别时投哪边),再宣布方法「逆向归纳」,从 2 人残局逐层推回 5 人并给出 A=98 的分配,最后补一句工程启示。答出数字是及格线,讲清「收买对象永远是下一轮拿 0 的人、每人只值 1 枚」才是加分项。你第一次做这道题时,是顺着推还是倒着推的?有没有被「平票算不算过」坑过?欢迎讲讲。