弄懂“三门问题”,成功概率翻倍,来用代码验证一下 三门问题

看到一段关于“三门问题”的视频,第一感觉就是视频的结论有误。本想一笑了之,但看了评论,迷惑了:三门问题的答案到底是什么?

作为勤学好问的码农,不知道最终答案,还是很难受的,于是深入研究一下,发现”小丑竟然是自己“。如果你想挑战一下自己,可以先跳过推理和结论部分,自己先得出一个答案,然后再看看是否正确。

一条朋友圈

在花了一个小时,弄懂三门问题之后,发了一条这样的朋友圈:

image-20211031201436187

三门问题:有三扇门,其中一扇后面是汽车,另外两扇是山羊。当你选择一扇门后,主持人从另外两扇门中打开一扇有山羊的。那么,此时换门是否会增加获得汽车的概率?

第一次错:直觉,换与不换都是1/2的概率;差点止步于此,得出结论:都是骗人的。

第二次错:列举,(选1,去2,换)、(选2,去1,换)、(选3,去1,不换)、(选3、去2、不换),看似概率依旧是1/2。但这里犯了一个错误,没引入首选的概率,也就是后两种情况不能按1/4算,只能按1/6算。

第三次引入概率:1/3(选1,去2,换)、1/3(选2,去1,换)、1/6(1/3 * 1/2)(选3,去1,不换)、1/6(1/3 * 1/2)(选3、去2、不换),后两项合计只有1/3概率。

所以,三门问题的答案是:选择换。概率会从原来的1/3,变成2/3;

通过这个问题在想:有时候,坚持可能是错的,可能是主观判断,可能环境已经发生了变化;但有时候又要坚持,要坚持对答案的怀疑,不断寻找答案。

如果从底层逻辑来说就是:坚持动态的看待问题。也就是:士别三日当刮目相待。

发完这条朋友圈,感觉这个问题有必要通过程序实现一下,同时写篇文章分享出来,于是就有了这篇文章。

如果上面的分析没看懂,也没关系,下面就结合代码再分析实践一下。

三门问题

三门问题出自美国的电视游戏节目Let’s Make a Deal,问题名字来自该节目的主持人蒙提·霍尔(Monty Hall)。

问题场景:

参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门可赢得该汽车,另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门是否会增加参赛者赢得汽车的机率。

据说,90%的人都选择了不换。你的选择是什么呢?

概率分析

先看下图,存在汽车、山羊1、山羊2,三个门:

image-20211031203316735

选手选择三个门的概率都是三分之一,下面进行具体的假设:

  • 假设选手选择了山羊1,那么主持人打的门只能是山羊2,因为有汽车的门是不能打开的。这种情况发生的概率为:1/3(选手选择山羊1的概率)* 1(主持人的选择是确定的) = 1/3;此时如果,则赢得汽车;
  • 假设选手选择了山羊2,那么主持人打的门只能是山羊1,因为有汽车的门是不能打开的。这种情况发生的概率为:1/3(选手选择山羊2的概率)* 1(主持人的选择是确定的) = 1/3;此时如果,则赢得汽车;
  • 假设选手选择了汽车,那么主持人有两种打开选择:山羊1和山羊2。主持人选择山羊1的概率:1/3(选手选择汽车的概率)* 1/2(主持人二选一) = 1/6;主持人选择山羊2的概率:1/3(选手选择汽车的概率)* 1/2(主持人二选一) = 1/6;所以,当选手选择了汽车的门时,发生的概率为:1/3 * 1/2 + 1/3 * 1/2 = 1/3。此时如果不换,则赢得汽车;

很显然,三种情况发生的概率都为三分之一,换之后赢得汽车的概率是不换的2倍。也就是说:换之后,赢得汽车的概率变成了2/3。

程序演示

上面做了理论分析,下面写一段代码,来验证一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
ini复制代码public class ThreeDoors {

/**
* 随机选择器
*/
private static final Random RANDOM = new Random();

/**
* 成功总次数
*/
private static int SUCCESS_COUNT = 0;

/**
* 重复执行10w次
*/
private static final int PLAY_TIMES = 100000;

public static void main(String[] args) {

// 执行游戏10w次
for (int i = 0; i < PLAY_TIMES; i++) {
playGame();
}

// 计算选择"换"的概率
BigDecimal yield = new BigDecimal(SUCCESS_COUNT)
.divide(new BigDecimal(PLAY_TIMES), 4, RoundingMode.HALF_UP)
.multiply(new BigDecimal(100));
System.out.println("执行" + PLAY_TIMES + "次实验,选择【交换】的概率为:" + yield + "%");
}

public static void playGame() {

// 初始化三扇门,默认为false,都没有车
boolean door1 = false, door2 = false, door3 = false;

// 选手选择的门是否为汽车,true:是
boolean pickedDoor;
// 最后剩下的门是否为汽车,true:是
boolean leftDoor;

// 第一步:随机选择一扇门,放入汽车
switch (pickDoor(3)) {
case 1:
door1 = true;
break;
case 2:
door2 = true;
break;
case 3:
door3 = true;
break;
default:
System.out.println("异常数值");
break;
}

// 第二步:选手选择一扇门,依旧采用上面选门的算法
int playerPickedDoor = pickDoor(3);

// 第三步:主持人移除一扇有山羊的门
// 其中主持人只能二选一,移除1一扇门,相当于选择了另一扇门
if (playerPickedDoor == 1) {
// 选手选择门1
pickedDoor = door1;
// 如果门2有车,则只能移除门3
if (door2) {
leftDoor = door2;
} else if (door3) {
// 如果门3有车,则只能移除门2
leftDoor = door3;
} else {
// 两个门都没车,随机二选一
if (pickDoor(2) == 1) {
leftDoor = door2;
} else {
leftDoor = door3;
}
}
} else if (playerPickedDoor == 2) {
// 选手选择门2
pickedDoor = door2;
// 如果门1有车,则只能移除门3
if (door1) {
leftDoor = door1;
} else if (door3) {
// 如果门3有车,则只能移除门1
leftDoor = door3;
} else {
// 两个门都没车,随机二选一
if (pickDoor(2) == 1) {
leftDoor = door1;
} else {
leftDoor = door3;
}
}
} else {
// 选手选择门3
pickedDoor = door3;
// 如果门1有车,则只能移除门2
if (door1) {
leftDoor = door1;
} else if (door2) {
// 如果门2有车,则只能移除门1
leftDoor = door2;
} else {
// 两个门都没车,随机二选一
if (pickDoor(2) == 1) {
leftDoor = door1;
} else {
leftDoor = door2;
}
}
}

// 第四步:上述结果一定的情况,选手选择更换门
pickedDoor = leftDoor;

// 第五步:判断该门是否有车
if (pickedDoor) {
SUCCESS_COUNT++;
}
}

/**
* 随机选择一个门
*/
public static int pickDoor(int bound) {
return RANDOM.nextInt(bound) + 1;
}
}

上述实现方法,暂且未考虑算法优化,只是简单情况判断处理。

上述实现分以下几步:

  • 第一步:随机选择一扇门,放入汽车,这里采用Random随机数,如果对应的门后为车,则对应的值设置为true;
  • 第二步:选手选择一扇门,算法依旧采用Random随机数;
  • 第三步:在选手选择一扇门的前提下,主持人移除一扇没有汽车的门。这里并未处理移除的门,而是记录了移除之后剩下的那扇门的值。如果两扇门都没有车,则随机二选一。
  • 第四步:选手选择交换,即选手选择的门变成了剩下的那扇门。
  • 第五步:开门,验证,如果成功记录一次;
  • 第六步:执行10w次之后,计算百分比;

最终打印日志如下:

1
erlang复制代码执行100000次实验,选择【交换】的概率为:66.7500%

多执行几次,会发现几乎都在66%-67%之间,说明选择【换】,的确可以让成功的概率翻倍。

小结

最后,回顾一下整个过程:无意看到一条讲”三门问题“的视频,先是做出了直观判断(错误的),对别人的结论嗤之以鼻,然后发现许、异议。于是,开始寻求佐证,最终得到了正确的答案。

正像在朋友圈中说的:有时候,坚持可能是错的,可能是因为主观判断,也可能是因为环境已经发生了变化;但有时候又要坚持,要坚持对答案的怀疑,对答案的不断追寻。

这也应该是我们做事的底层逻辑,不能单靠【感觉】来判断,更多的要采用事实作为依据。特别是程序员,我们还可以用程序来解决类似的问题。

同时,你是否发现,用程序来解决生活中的一些问题,不也是很有意思的吗?

博主简介:《SpringBoot技术内幕》技术图书作者,酷爱钻研技术,写技术干货文章。

公众号:「程序新视界」,博主的公众号,欢迎关注~

技术交流:请联系博主微信号:zhuan2quan

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%