大家好,我是小白学编程。
最近同事问我一个问题,就是经典的三门问题,之前我也听过这个问题,但是没有去想过。今天用代码做了一个实验统计,统计结果如下:
一、问题
问题是这样的,有三道门,每道门后面放一样东西,分别是汽车、羊、羊。出题者是知道所有放置的位置的,选择者不知道放置的位置。当选择者选好一道门之后,出题者会打开另外一道后面放着羊的门,这时问选择者换不换门。意思就是换门选择到汽车的几率大还是不换门选择的汽车的几率大?那么,如果你是选择者,你会选择换门吗?
二、错误引导
你是否会有这样的想法?
当第一次选择时,门后面是汽车的概率是 1/3 ,当选择好之后,这时出题者打开一道后面是羊的门。打开这道门对你刚刚选择的门没有任何影响,刚刚选择的门后面放的是什么,现在放的还是什么,结果不会发生变化。假如现在重新再选一次,排除掉打开的那道门,还剩两道门,那么选择则到汽车的概率就是 1/2 。但是,题目中说的是换门,那么可以做两个假设:
三道门
假设一:第一次选择了 A 门,此时出题者打开的是 C 门,C门后面是羊,这时,如果选择者进行换门,则会换为 B 门;如果不换门,还是 A 门
假设二:第一次选择了 B 门,此时出题者打开的是 C 门,C门后面是羊,这时,如果选择者进行换门,则会换为 A 门;如果不换门,还是 B 门
打开一道门
那么,假设一中的换门的结果,和假设二中的不换结果是一样的;假设二中的换门的结果,和假设一中的不换的结果式样的。而且第一次选择哪个门都一样,所以换不换门结果都是一样的。
如果有这样的想法,那就时进入了误区,这个想法是不对的!
三、正确分析
当第一次选择时,不论选哪道门,选中汽车的概率都是 1/3 ,选中羊的概率羊的概率都是 2/3。那也就是说第一次选择大概率是错的,记住,第一次选则一道门,比如 A 门,大概率是错的。那么此时打开了 C 门,C 门后面是羊,那就剩下 B 门后面可能出现汽车了。既然 A 门大概率是错的,那么 B 门就大概率是对的,所以选择换门。
再换一种说法,第一次选择,不论选择哪道门,后面是汽车的概率都是 1/3 ,比如选择了 A 门。当选择一道门之后,出题人打开一道门,比如 C 门,C 门后面是羊,那么你知道了 C 门后面
打开门之前
打开门之后
的结果是羊,那么 C 门后面是汽车的概率就是 0 ,那么 B 门后面出现汽车的概率就是 2/3。
四、结论
打开门之后,肯定要选择换门,换门可以选则到汽车的概率大
五、实验代码
前面分析的可能有人还是疑惑,有点不敢相信,那么接下来就用代码测试一下,模拟做五轮实验进行比较,每轮做一千次选择
1、代码
private static final String CAR = "汽车";
@Test
public void test1(){
//换门的成功概率
List<String> changeRate = Lists.newArrayList();
//不换门的成功概率
List<String> notChangeRate = Lists.newArrayList();
for(int i = 0;i < 5; i++){
int successChange = 0;
int successNotChange = 0;
for(int j = 0;j < 1000;j++){
if(threeDoor(true)){
successChange++;
}
if(threeDoor(false)){
successNotChange++;
}
}
String resultChange = successChange * 100.0 / 1000 + "%";
changeRate.add(resultChange);
String resultNotChange = successNotChange * 100.0 / 1000 + "%";
notChangeRate.add(resultNotChange);
}
System.out.println("对三门问题做调研,换门做五次统计,不换门做五次统计,每次统计做1000次实验,成功选中汽车的概率输出结果如下:");
System.out.println("—————————————————————————————————————————————————————————————————————————————————————————");
for(int i = 0; i <= 5;i++){
if(i == 0){
System.out.print("|\t\t|");
} else {
System.out.print("\t第 " + i + " 次统计\t|");
}
}
System.out.println("\n—————————————————————————————————————————————————————————————————————————————————————————");
for(int i = 0; i <= 5;i++){
if(i == 0){
System.out.print("|换门\t|");
} else {
System.out.print("\t" + changeRate.get(i - 1) + "\t\t|");
}
}
System.out.println("\n—————————————————————————————————————————————————————————————————————————————————————————");
for(int i = 0; i <= 5;i++){
if(i == 0){
System.out.print("|不换门\t|");
} else {
System.out.print("\t" + notChangeRate.get(i - 1) + "\t\t|");
}
}
System.out.println("\n—————————————————————————————————————————————————————————————————————————————————————————");
}
/**
* 选择实验
* @param changeFlag true 为换门,false 坚持不换门
* @return
*/
public boolean threeDoor(boolean changeFlag){
//已知的门后放置的内容
List<String> list = Lists.newArrayList("汽车","羊","羊");
//三道门
List<String> threeDoors = Lists.newArrayList();
Random rand = new Random();
//随机向门后放东西
for(int i = 3; i > 0; i--){
int index = rand.nextInt(9 + (3 - i)) % i;
String door = list.get(index);
list.remove(index);
threeDoors.add(door);
}
//获取放汽车的门
int carDoor = threeDoors.indexOf(CAR);
//随机选一道门
int selectedDoor = rand.nextInt(9) % 3;
//可以打开的门
List<Integer> enableOpenDoors = Lists.newArrayList();
for(int i = 0;i <= 2; i++){
if(carDoor != i && selectedDoor != i){
enableOpenDoors.add(i);
}
}
int size = enableOpenDoors.size();
int openIndex = rand.nextInt(9 + (3 - size)) % size;
//打开的门
int openDoor = enableOpenDoors.get(openIndex);
int resultDoor = selectedDoor;
if(changeFlag){
//换门
for (int i = 0; i <= 2; i++){
if(i != selectedDoor && i != openDoor){
resultDoor = i;
break;
}
}
}
//打开选择的门
String result = threeDoors.get(resultDoor);
return result.equals(CAR);
}
2、实验测试结果
我们不能改变过去,但是可以选择如何面对未来
我觉着这问题还挺有意思的,不知道你感觉如何