我的编程技术分享

首页 / 博客 / 有趣的《三门实验》,颠覆了我的认知!

有趣的《三门实验》,颠覆了我的认知!

3429 次阅读 ,发布于 : 2023-11-29

大家好,我是Tabber,今天给大家分享一个有趣的数学实验《三门实验》,

这个实验直接颠覆了我的直觉认知,What ? 不可能?肯定是你算错了?

下面让我们一起看下这个有趣的实验吧。

(文末有验证代码示例,可以自己跑下结果,看是否和自己预想的一致)


什么是三门问题?

这个游戏的玩法是:参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,而另外两扇门后面则各藏有一只山羊,选中后面有车的那扇门就可以赢得该汽车。当参赛者选定了一扇门,但未去开启它的时候,节目主持人会开启剩下两扇门的其中一扇有山羊的门(主持人知道每个门后面是什么)。

这个时候,主持人会给参赛者两个选择:

  • 换另一扇仍然关上的门
  • 坚持选择当前已选的门

问题是:哪一种选择会否增加参赛者赢得汽车的概率?

请你思考 5秒钟 后做出自己的选择后,咱们继续开车…


揭晓答案

正确的选择:选择换门的胜率更大

  • 选择换门的胜率为66.6%
  • 选择不换的胜率为33.3%

知道答案哪一刻,我不知道你的表情是怎样的,但我的表情应该是这样的

想必大家的思路都是这样的:

第一次选择,我的胜率为33.3%,主持人打开一个为山羊的门后,只剩下一辆车和一只山羊,很明显剩余两扇门为车的概率都应为50%,所以我选择不换的概率都应为50%

嗡,再想了想,好像没啥问题也,正确的选择怎么会是换的胜率更大呢?

验证过程


无法理解答案后,作为一名软件工程师,咱们最擅长的不就是写代码嘛,来搞一套,验证一下,肯定是出题人搞错了,我要用大量数据验证摆在你面前,看看谁错了?一脸傲娇!

  1. /**
  2. * 验证 三门实验 示例
  3. * author:Java知己
  4. */
  5. public class ThreeDoorExperiment {
  6. /**
  7. * 示例比较简单,直接一个main方法搞定
  8. * 也方便小伙伴们直接下载测试
  9. * @param args
  10. */
  11. public static void main(String[] args) {
  12. //成功次数
  13. int success = 0;
  14. //实验次数
  15. int count = 0;
  16. //三个门,0表示羊,1表示车
  17. int[] doors = {0, 0, 0};
  18. Random random = new Random();
  19. while (true){
  20. // 每次重置三个门为羊
  21. for(int i=0;i<doors.length;i++){
  22. doors[i] = 0;
  23. }
  24. // 将随机一个门置为车
  25. int right = random.nextInt(doors.length);
  26. doors[right] = 1;
  27. // 我随机选择一个门(第一次选择)
  28. int my_select_first = random.nextInt(doors.length);
  29. // 计算剩余两个门的和,判断是否有车
  30. int result = 0;
  31. // 剩余门的索引
  32. List<Integer> remain_doors_index_list = new ArrayList<>();
  33. for(int i=0;i<doors.length;i++){
  34. if(i == my_select_first){
  35. continue;
  36. }
  37. remain_doors_index_list.add(i);
  38. result += doors[i];
  39. }
  40. //主持人打开门的第几个门
  41. int opened_rel = -1;
  42. // 主持人随机打开另外两个中的一个(必须是羊的一个门)
  43. if(result == 0){
  44. // 如果两个门都是羊,随机一个
  45. int remain_door_random = random.nextInt( remain_doors_index_list.size() );
  46. opened_rel = remain_doors_index_list.get(remain_door_random);
  47. }else{
  48. // 如果两个门只有一个是羊,只能打开这一个
  49. for(int index:remain_doors_index_list){
  50. if(doors[index] == 0){
  51. opened_rel = index;
  52. }
  53. }
  54. }
  55. // 是否换另一个门
  56. boolean switch_door = true;
  57. //如果选择换,第二次的选择索引
  58. Integer my_select_two = null;
  59. if(switch_door){
  60. for(int i=0;i<doors.length;i++){
  61. if(i != my_select_first && i != opened_rel){
  62. my_select_two = i;
  63. break;
  64. }
  65. }
  66. }
  67. // 判断我的选择是否正确
  68. if(switch_door){
  69. if(my_select_two == right){
  70. success ++;
  71. }
  72. }else{
  73. if(my_select_first == right){
  74. success ++;
  75. }
  76. }
  77. count ++;
  78. // 当前成功概率
  79. System.out.println("当前门状态:" + Arrays.toString(doors));
  80. if(switch_door){
  81. System.out.println(String.format("我的选择:%d,打开门为:%d,更换的门为:%d,正确的门为:%d",my_select_first, opened_rel,my_select_two, right));
  82. }else{
  83. System.out.println(String.format("我的选择:%d,打开门为:%d,正确的门为:%d",my_select_first, opened_rel, right));
  84. }
  85. double successP = success * 100 / (double)count;
  86. System.out.println(String.format("当前我的成功概率为:%.2f%%,总实验次数为:%d",successP, count));
  87. System.out.println("-------------------------------------------------------------------");
  88. }
  89. }
  90. }

实验结果

来咱们先跑一下

换门的胜率是多少?

  1. 当前门状态:[0, 1, 0]
  2. 我的选择:0,打开门为:2,更换的门为:1,正确的门为:1
  3. 当前我的成功概率为:100.00%,总实验次数为:1
  4. -------------------------------------------------------------------
  5. 当前门状态:[0, 0, 1]
  6. 我的选择:1,打开门为:0,更换的门为:2,正确的门为:2
  7. 当前我的成功概率为:100.00%,总实验次数为:2
  8. -------------------------------------------------------------------
  9. 当前门状态:[1, 0, 0]
  10. 我的选择:0,打开门为:2,更换的门为:1,正确的门为:0
  11. 当前我的成功概率为:66.67%,总实验次数为:3
  12. -------------------------------------------------------------------
  13. ...
  14. ...省略中间N次过程
  15. ...
  16. 当前门状态:[0, 0, 1]
  17. 我的选择:1,打开门为:0,更换的门为:2,正确的门为:2
  18. 当前我的成功概率为:66.64%,总实验次数为:253603
  19. -------------------------------------------------------------------
  20. 当前门状态:[0, 1, 0]
  21. 我的选择:2,打开门为:0,更换的门为:1,正确的门为:1
  22. 当前我的成功概率为:66.64%,总实验次数为:253604
  23. -------------------------------------------------------------------
  24. 当前门状态:[0, 0, 1]
  25. 我的选择:0,打开门为:1,更换的门为:2,正确的门为:2
  26. 当前我的成功概率为:66.64%,总实验次数为:253605
  27. -------------------------------------------------------------------

再来一次不换的胜率是多少?

  1. //是否换另一个门
  2. boolean switch_door = false;

修改switch_door 为 false,表示在第二次选择时,不更换门

  1. 修改switch_door false,表示在第二次选择时,不更换门
  2. 当前门状态:[1, 0, 0]
  3. 我的选择:1,打开门为:2,正确的门为:0
  4. 当前我的成功概率为:0.00%,总实验次数为:1
  5. -------------------------------------------------------------------
  6. 当前门状态:[0, 1, 0]
  7. 我的选择:1,打开门为:2,正确的门为:1
  8. 当前我的成功概率为:50.00%,总实验次数为:2
  9. -------------------------------------------------------------------
  10. 当前门状态:[0, 1, 0]
  11. 我的选择:0,打开门为:2,正确的门为:1
  12. 当前我的成功概率为:33.33%,总实验次数为:3
  13. -------------------------------------------------------------------
  14. ...
  15. ...省略中间N次过程
  16. ...
  17. 当前门状态:[0, 0, 1]
  18. 我的选择:0,打开门为:1,正确的门为:2
  19. 当前我的成功概率为:33.34%,总实验次数为:206159
  20. -------------------------------------------------------------------
  21. 当前门状态:[0, 1, 0]
  22. 我的选择:0,打开门为:2,正确的门为:1
  23. 当前我的成功概率为:33.34%,总实验次数为:206160
  24. -------------------------------------------------------------------
  25. 当前门状态:[1, 0, 0]
  26. 我的选择:1,打开门为:2,正确的门为:0
  27. 当前我的成功概率为:33.34%,总实验次数为:206161
  28. -------------------------------------------------------------------

啊,打脸了,验证完的确是自己的直觉错了,但究竟是哪个环节出了问题呢?

认知分析

初始概率会随着后续事件不断调整

我们第一次选择后的概率为33.3%,这个是毫无疑问的,但后续事件(主持人开一扇为羊的门)后,原本门的概率都发生的改变。

站在全局的角度,你选择之后,主持人会开一个有山羊的门;你不换门,概率固定为1/3;你换门,相当于主持人给你排除了一个错误答案,所以概率变成了2/3。

如果是主持人已经开了门的时候,这个时候你再进行第一次选择,那么这个时候二选一,概率才为50%。

总结

这条问题亦被叫做蒙提霍尔悖论:虽然该问题的答案在逻辑上并不自相矛盾,但十分违反直觉。这问题曾引起一阵热烈的讨论。

我们看到,一个看似毫无意义的行为,竟然能为决策者提供如此多的信息。那么在更为复杂的博弈中,找到对手留下的蛛丝马迹便尤为重要。

有热门推荐

  1. 再见了Xshell、iTerm2,这款开源的终端工具真香!

  2. 95年女程序员内心的感受

  3. Intellij IDEA 2022 正式发布,这些功能还真不错

  4. 又一款接私活神器!SpringBoot+Vue通用后台管理系统

欢迎访问Tabber的博客!
×