大家好,我是Tabber,今天给大家分享一个有趣的数学实验《三门实验》,
这个实验直接颠覆了我的直觉认知,What ? 不可能?肯定是你算错了?
下面让我们一起看下这个有趣的实验吧。
(文末有验证代码示例,可以自己跑下结果,看是否和自己预想的一致)
什么是三门问题?
这个游戏的玩法是:参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,而另外两扇门后面则各藏有一只山羊,选中后面有车的那扇门就可以赢得该汽车。当参赛者选定了一扇门,但未去开启它的时候,节目主持人会开启剩下两扇门的其中一扇有山羊的门(主持人知道每个门后面是什么)。
这个时候,主持人会给参赛者两个选择:
- 换另一扇仍然关上的门
- 坚持选择当前已选的门
问题是:哪一种选择会否增加参赛者赢得汽车的概率?
请你思考 5秒钟 后做出自己的选择后,咱们继续开车…
揭晓答案
正确的选择:选择换门的胜率更大
- 选择换门的胜率为66.6%
- 选择不换的胜率为33.3%
知道答案哪一刻,我不知道你的表情是怎样的,但我的表情应该是这样的
想必大家的思路都是这样的:
第一次选择,我的胜率为33.3%,主持人打开一个为山羊的门后,只剩下一辆车和一只山羊,很明显剩余两扇门为车的概率都应为50%,所以我选择换与不换的概率都应为50%。
嗡,再想了想,好像没啥问题也,正确的选择怎么会是换的胜率更大呢?
验证过程
无法理解答案后,作为一名软件工程师,咱们最擅长的不就是写代码嘛,来搞一套,验证一下,肯定是出题人搞错了,我要用大量数据验证摆在你面前,看看谁错了?一脸傲娇!
/**
* 验证 三门实验 示例
* author:Java知己
*/
public class ThreeDoorExperiment {
/**
* 示例比较简单,直接一个main方法搞定
* 也方便小伙伴们直接下载测试
* @param args
*/
public static void main(String[] args) {
//成功次数
int success = 0;
//实验次数
int count = 0;
//三个门,0表示羊,1表示车
int[] doors = {0, 0, 0};
Random random = new Random();
while (true){
// 每次重置三个门为羊
for(int i=0;i<doors.length;i++){
doors[i] = 0;
}
// 将随机一个门置为车
int right = random.nextInt(doors.length);
doors[right] = 1;
// 我随机选择一个门(第一次选择)
int my_select_first = random.nextInt(doors.length);
// 计算剩余两个门的和,判断是否有车
int result = 0;
// 剩余门的索引
List<Integer> remain_doors_index_list = new ArrayList<>();
for(int i=0;i<doors.length;i++){
if(i == my_select_first){
continue;
}
remain_doors_index_list.add(i);
result += doors[i];
}
//主持人打开门的第几个门
int opened_rel = -1;
// 主持人随机打开另外两个中的一个(必须是羊的一个门)
if(result == 0){
// 如果两个门都是羊,随机一个
int remain_door_random = random.nextInt( remain_doors_index_list.size() );
opened_rel = remain_doors_index_list.get(remain_door_random);
}else{
// 如果两个门只有一个是羊,只能打开这一个
for(int index:remain_doors_index_list){
if(doors[index] == 0){
opened_rel = index;
}
}
}
// 是否换另一个门
boolean switch_door = true;
//如果选择换,第二次的选择索引
Integer my_select_two = null;
if(switch_door){
for(int i=0;i<doors.length;i++){
if(i != my_select_first && i != opened_rel){
my_select_two = i;
break;
}
}
}
// 判断我的选择是否正确
if(switch_door){
if(my_select_two == right){
success ++;
}
}else{
if(my_select_first == right){
success ++;
}
}
count ++;
// 当前成功概率
System.out.println("当前门状态:" + Arrays.toString(doors));
if(switch_door){
System.out.println(String.format("我的选择:%d,打开门为:%d,更换的门为:%d,正确的门为:%d",my_select_first, opened_rel,my_select_two, right));
}else{
System.out.println(String.format("我的选择:%d,打开门为:%d,正确的门为:%d",my_select_first, opened_rel, right));
}
double successP = success * 100 / (double)count;
System.out.println(String.format("当前我的成功概率为:%.2f%%,总实验次数为:%d",successP, count));
System.out.println("-------------------------------------------------------------------");
}
}
}
实验结果
来咱们先跑一下
换门的胜率是多少?
当前门状态:[0, 1, 0]
我的选择:0,打开门为:2,更换的门为:1,正确的门为:1
当前我的成功概率为:100.00%,总实验次数为:1
-------------------------------------------------------------------
当前门状态:[0, 0, 1]
我的选择:1,打开门为:0,更换的门为:2,正确的门为:2
当前我的成功概率为:100.00%,总实验次数为:2
-------------------------------------------------------------------
当前门状态:[1, 0, 0]
我的选择:0,打开门为:2,更换的门为:1,正确的门为:0
当前我的成功概率为:66.67%,总实验次数为:3
-------------------------------------------------------------------
...
...省略中间N次过程
...
当前门状态:[0, 0, 1]
我的选择:1,打开门为:0,更换的门为:2,正确的门为:2
当前我的成功概率为:66.64%,总实验次数为:253603
-------------------------------------------------------------------
当前门状态:[0, 1, 0]
我的选择:2,打开门为:0,更换的门为:1,正确的门为:1
当前我的成功概率为:66.64%,总实验次数为:253604
-------------------------------------------------------------------
当前门状态:[0, 0, 1]
我的选择:0,打开门为:1,更换的门为:2,正确的门为:2
当前我的成功概率为:66.64%,总实验次数为:253605
-------------------------------------------------------------------
再来一次不换的胜率是多少?
//是否换另一个门
boolean switch_door = false;
修改switch_door 为 false,表示在第二次选择时,不更换门
修改switch_door 为 false,表示在第二次选择时,不更换门
当前门状态:[1, 0, 0]
我的选择:1,打开门为:2,正确的门为:0
当前我的成功概率为:0.00%,总实验次数为:1
-------------------------------------------------------------------
当前门状态:[0, 1, 0]
我的选择:1,打开门为:2,正确的门为:1
当前我的成功概率为:50.00%,总实验次数为:2
-------------------------------------------------------------------
当前门状态:[0, 1, 0]
我的选择:0,打开门为:2,正确的门为:1
当前我的成功概率为:33.33%,总实验次数为:3
-------------------------------------------------------------------
...
...省略中间N次过程
...
当前门状态:[0, 0, 1]
我的选择:0,打开门为:1,正确的门为:2
当前我的成功概率为:33.34%,总实验次数为:206159
-------------------------------------------------------------------
当前门状态:[0, 1, 0]
我的选择:0,打开门为:2,正确的门为:1
当前我的成功概率为:33.34%,总实验次数为:206160
-------------------------------------------------------------------
当前门状态:[1, 0, 0]
我的选择:1,打开门为:2,正确的门为:0
当前我的成功概率为:33.34%,总实验次数为:206161
-------------------------------------------------------------------
啊,打脸了,验证完的确是自己的直觉错了,但究竟是哪个环节出了问题呢?
认知分析
初始概率会随着后续事件不断调整
我们第一次选择后的概率为33.3%,这个是毫无疑问的,但后续事件(主持人开一扇为羊的门)后,原本门的概率都发生的改变。
站在全局的角度,你选择之后,主持人会开一个有山羊的门;你不换门,概率固定为1/3;你换门,相当于主持人给你排除了一个错误答案,所以概率变成了2/3。
如果是主持人已经开了门的时候,这个时候你再进行第一次选择,那么这个时候二选一,概率才为50%。
总结
这条问题亦被叫做蒙提霍尔悖论:虽然该问题的答案在逻辑上并不自相矛盾,但十分违反直觉。这问题曾引起一阵热烈的讨论。
我们看到,一个看似毫无意义的行为,竟然能为决策者提供如此多的信息。那么在更为复杂的博弈中,找到对手留下的蛛丝马迹便尤为重要。
有热门推荐