如何证明该算法能正确计算抽屉欧元的目标条件概率?
问题背景
办公室内有一张桌子,存在欧元的概率为50%;该桌子有3个抽屉,若桌子内有欧元,则欧元等概率分布在任一抽屉中。问题:若已在前两个抽屉中未找到欧元,欧元在第三个抽屉中的概率是多少?
你的代码与运行输出
代码片段
int iterations = 10000; int desk;// 0 or 1 - 50% int[] foundEuro = new int[5]; for (int i=1; i <= iterations; i++){ desk = (int) (Math.random() * 2); if ( desk == 0){ // 桌子内有欧元 int drawer = (int) (Math.random() * 3); if ( drawer == 0){ foundEuro[drawer]++; // 欧元在抽屉1 } else { foundEuro[drawer]++; // 欧元在抽屉2 foundEuro[drawer+1]++; // 欧元在抽屉3 } } else { foundEuro[desk]++; } } showResult(foundEuro); float probability = ( ((float) foundEuro[0]) / iterations) * 100; System.out.printf("%.2f%%", probability);
运行输出
Euro in drawer 1: 1638 Euro in drawer 2: 6622 Euro in drawer 3: 3343 16,38%
你的疑问
我认为代码无错误,应能输出正确结果,但不确定该结果是否为“前两个抽屉未找到时欧元在第三个抽屉”的正确概率,如何证明该算法给出的概率正确?
首先得说,你的代码逻辑存在几个关键错误,导致输出结果完全不符合问题要求。咱们先拆解问题核心:我们要算的是「在前两个抽屉都没找到欧元」这个前提下,「第三个抽屉有欧元」的条件概率,而你的代码既没正确模拟这个前提,也没正确统计符合条件的样本。
代码里的问题点
- 变量逻辑混乱:你用
desk=0表示桌子有欧元,desk=1表示没有,但桌子没有欧元时,所有抽屉都空,根本不应该给foundEuro[desk]计数——这完全是无意义的操作,会打乱统计结果。 - 抽屉计数错误:当桌子有欧元时,你在
drawer!=0的分支里同时给两个抽屉的计数加1,这相当于把欧元同时放在了两个抽屉里,完全违背了“欧元只在一个抽屉”的设定。 - 没筛选条件样本:问题要求只看「前两个抽屉没欧元」的情况,但你的代码用了所有迭代次数做分母,完全忽略了条件概率的核心——只统计符合前提的样本。
用数学推导证明正确概率(贝叶斯定理)
咱们用贝叶斯定理来算正确结果,这样就能明确标准:
- 设事件A:桌子里有欧元,P(A)=0.5
- 事件B:前两个抽屉都没有欧元
- 我们要算的是:P(第三个抽屉有欧元 | B)
步骤1:计算P(B)(前两个抽屉都空的总概率)
P(B) = P(B|A)*P(A) + P(B|¬A)*P(¬A)
- P(B|A):桌子有欧元时,前两个抽屉都空的概率 = 1/3(只有欧元在第三个抽屉时,前两个才空)
- P(B|¬A):桌子没有欧元时,前两个抽屉都空的概率 = 1
所以P(B) = (1/3)0.5 + 10.5 = 2/3
步骤2:计算条件概率
我们要求的是「前两个抽屉空,且第三个有欧元」的概率,除以「前两个抽屉空」的概率:
分子:P(第三个抽屉有欧元且B) = P(A)P(欧元在第三个抽屉) = 0.5(1/3) = 1/6
最终概率 = (1/6) / (2/3) = 1/4 = 25%
修正后的模拟代码(验证正确结果)
我们需要严格模拟问题场景:只统计「前两个抽屉空」的样本,再在这些样本里数「第三个抽屉有欧元」的次数:
int iterations = 100000; int totalValidCases = 0; // 前两个抽屉都没找到欧元的总次数 int euroInThirdDrawer = 0; // 符合前提且第三个抽屉有欧元的次数 for (int i = 0; i < iterations; i++) { // 50%概率桌子有欧元 boolean hasEuro = Math.random() < 0.5; int euroDrawer = -1; // -1代表桌子没有欧元 if (hasEuro) { // 欧元等概率在三个抽屉(0=抽屉1,1=抽屉2,2=抽屉3) euroDrawer = (int) (Math.random() * 3); } // 判断前两个抽屉是否都空:要么桌子没欧元,要么欧元在第三个抽屉 boolean firstTwoEmpty = (euroDrawer == -1) || (euroDrawer == 2); if (firstTwoEmpty) { totalValidCases++; if (euroDrawer == 2) { euroInThirdDrawer++; } } } // 计算条件概率 double probability = ((double) euroInThirdDrawer / totalValidCases) * 100; System.out.printf("前两个抽屉未找到时,欧元在第三个抽屉的概率:%.2f%%%n", probability);
运行这段代码,结果会稳定在25%左右,和我们的数学推导完全一致。
结论
你的原代码因为逻辑错误,没有正确模拟问题的前提条件,所以输出的16.38%是错误的。通过贝叶斯定理的数学推导,我们可以确定正确概率是25%;而修正后的模拟代码也验证了这个结果,因为它严格遵循了问题要求:只统计符合「前两个抽屉空」的样本,再计算其中第三个抽屉有欧元的比例。
内容的提问来源于stack exchange,提问作者TorbenIT

