三门问题(Monty Hall problem)
昨天在刷douyin时,恰巧刷到了一条关于数学概率的小视频。点赞人数很多,评论人数也很多,重点是视频的内容谈到的三门问题确实非常的吸引人去思考(反正我有被吸引到,谢谢)。。
视频很短,结尾处就把“答案”说出来了。
当然,以我这脑瓜子,拿着手机愣是想了半个多小时,依然没弄明白为啥我的想法与公布的答案不符,一度让我怀疑我的智商。翻看了一下评论区,大家的想法和意见也都有分歧,有和我想的一样的,也有和公布的答案一样的,还很热心的把原因讲解了一遍,,,嗯,我还是没搞懂。
进入正题
首先看一下什么是“三门问题”。接下来是度娘登场时间~~~
三门问题(Monty Hall problem)亦称为蒙提霍尔问题、蒙特霍问题或蒙提霍尔悖论,大致出自美国的电视游戏节目Let's Make a Deal。问题名字来自该节目的主持人蒙提·霍尔(Monty Hall)。参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门可赢得该汽车,另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门会否增加参赛者赢得汽车的机率。如果严格按照上述的条件,那么答案是会。不换门的话,赢得汽车的几率是1/3。换门的话,赢得汽车的几率是2/3。
以上的说法可能不是很严谨哈,下面给出更为严谨的陈述:
-
现在有三扇门,只有一扇门有汽车,其余两扇门的都是山羊。
-
汽车事前是等可能地被放置于三扇门的其中一扇后面。
-
参赛者在三扇门中挑选一扇。他在挑选前并不知道任意一扇门后面是什麽。
-
主持人知道每扇门后面有什么。
-
如果参赛者挑了一扇有山羊的门,主持人必须挑另一扇有山羊的门。
-
如果参赛者挑了一扇有汽车的门,主持人等可能地在另外两扇有山羊的门中挑一扇门。
-
参赛者会被问是否保持他的原来选择,还是转而选择剩下的那一扇门。
嗯,陈述看完,就要讲讲为啥换门后中奖的概率要高了。(解法很多,这里只列举一种比较通俗易懂的解题思路,依然来自度娘,,,感谢度娘的大力支持,谢谢。。)
当参赛者转向另一扇门而不是维持原先的选择时,赢得汽车的机会将会加倍。
有三种可能的情况,全部都有相等的可能性(1/3):
1、参赛者挑山羊一号,主持人挑山羊二号。转换将赢得汽车。
2、参赛者挑山羊二号,主持人挑山羊一号。转换将赢得汽车。
3、“参赛者挑汽车,主持人挑羊一号。转换将失败”,和“参赛者挑汽车,主持人挑羊二号。转换将失败。”此情况的可能性为:1/3 * 1/2 + 1/3 * 1/2 = 1/3。
实践部分
既然我无法用脑瓜子想透它,就要用行动证明它!
我预想的证明方法就两种:
方法一:用扑克牌
首先用两张一样数字的扑克代表山羊,一张不一样数字的扑克代表汽车,然后叫上你的小伙伴,愉(枯)快(燥)的玩游戏!你的小伙伴扮演主持人,你就是玩家,根据规则开始不断地猜猜猜、换换换、不换不换我不换,同时记录猜中的次数、不中的次数与总次数,最后再计算换与不换能猜中汽车的概率。
这个方法确实简单,但是也确实耗时。而且我们知道,概率这东西,尝试的次数越多,才越接近真实情况。玩个十万次估计能把人玩废,哈哈哈。
方法二:用代码模拟
上代码~~~(代码很简单,学过java的都知道)
import java.util.Random;
import java.util.Scanner;
/**
* @Description 三门问题模拟
* @Author HeHuanxing
* @Date 2020/12/13 22:42
* @UpdateUser
* @Version 1.0
*/
public class ThreeQuestionsTest {
// 测试的次数(即竞猜的总次数)
private static float numberOfGuesses = -1;
// 玩家选择的门编号
private static int selectedNumber = -1;
// 主持人开启背后有山羊的门编号
private static int doorOpenedIndex = -1;
// 猜中的总次数
private static float numberOfAwards = 0L;
// 未猜中的总次数
private static float noAwards = 0L;
// 玩家是否更换所选择的门(默认不更改)
private static String isChangeChoice = "N";
// 使用长度为3的数组表示三个门,初始值为-1,表示不代表任何东西;使用1表示汽车,2表示羊
private static int[] doors = new int[]{-1, -1, -1};
// 使用Random对象获取随机数,模拟随机分配汽车和山羊
private static Random randomForAssigned = new Random();
// 同样使用Random对象获取随机数,模拟随机选择一扇门
private static Random randomForSelection = new Random();
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入想要测试的次数:");
numberOfGuesses = input.nextFloat();
System.out.println("是否更换所选择的门?(Y/N)");
isChangeChoice = input.next();
System.out.print("输入完成,总的竞猜次数为" + numberOfGuesses + "次,并且");
if (isChangeChoice.equalsIgnoreCase("N")) {
System.out.println("当主持人询问是否更换门时,玩家选择不更换");
} else {
System.out.println("当主持人询问是否更换门时,玩家选择更换");
}
startTheGuessingGame();
}
private static void startTheGuessingGame() {
for (int num = 1; num <= numberOfGuesses; num++) {
// 每进行一次选择,均需要初始化一次各个参数,模拟这是一场新的竞猜环节
init();
// 随机在三个门后分配汽车和山羊
randomlyAssigned();
// 随机选择任意一扇门
randomSelection();
// 主持人开启背后有山羊的门,并根据玩家是否愿意换门来进行交换门编号
askAndDetermineTheFinalChoice();
// 累计猜中的次数与未猜中的次数
if (doors[selectedNumber] == 1) {
numberOfAwards++;
} else {
noAwards++;
}
}
System.out.println("猜中汽车的概率是:" + numberOfAwards/numberOfGuesses);
System.out.println("猜不中汽车的概率是:" + noAwards/numberOfGuesses);
}
/**
* 将各个参数初始化
*/
private static void init() {
selectedNumber = -1;
doorOpenedIndex = -1;
doors[0] = -1;
doors[1] = -1;
doors[2] = -1;
}
/**
* 随机在三个门后分配汽车和山羊
* 编号说明:使用1表示汽车,使用2表示山羊
*/
private static void randomlyAssigned() {
int carIndex = randomForAssigned.nextInt(3);
doors[carIndex] = 1;
for (int index = 0; index < doors.length; index++) {
if (index != carIndex) {
doors[index] = 2;
}
}
}
/**
* 随机选择任意一扇门
*/
private static void randomSelection() {
selectedNumber = randomForSelection.nextInt(3);
}
/**
* 主持人开启背后有山羊的门,并根据玩家的换门意愿来进行下一步操作
* 需要明确的是:主持人一定知道门后是汽车还是山羊,打开的一定是山羊的门
*/
private static void askAndDetermineTheFinalChoice() {
// 确定被主持人打开的门编号
for (int index = 0; index < doors.length; index++) {
if (selectedNumber != index && doors[index] == 2) {
doorOpenedIndex = index;
break;
}
}
if (isChangeChoice.equalsIgnoreCase("Y")) {
// 若玩家愿意更换前面选中的那一扇门,则玩家交换后选中的即是另一扇没打开的门
for (int index = 0; index < doors.length; index++) {
if (selectedNumber != index && doorOpenedIndex != index) {
selectedNumber = index;
break;
}
}
} else {
// 玩家不愿意更换前面选中的那一扇门,则保持原状
// do nothing
}
}
}
以下是测试结果:
更换门的测试:
请输入想要测试的次数:
1000000
是否更换所选择的门?(Y/N)
Y
输入完成,总的竞猜次数为1000000.0次,并且当主持人询问是否更换门时,玩家选择更换
猜中汽车的概率是:0.666836
猜不中汽车的概率是:0.333164
不更换门的测试:
请输入想要测试的次数:
5000000
是否更换所选择的门?(Y/N)
N
输入完成,总的竞猜次数为5000000.0次,并且当主持人询问是否更换门时,玩家选择不更换
猜中汽车的概率是:0.3335684
猜不中汽车的概率是:0.6664316
不论以扑克牌的方式方式验证,还是使用代码去测试,确实换门比不换门,猜中汽车的概率要高。不换门则仅有1/3概率,换了之后,有2/3概率把车开回家!
小尾巴~~~~~
博客账号申请了这么久,却一直没写过文章,这个就当做是一个开头吧。祝自己也祝所有人都能前程似锦 [手动加笑脸]