【随笔】关于玛丽莲问题的一些思考(附c++代码证明)
玛丽莲问题是一个十分有趣的概率问题,首先,它是违反人的第一直觉的。为什么会违反直觉?我们直接来看题目吧。
玛丽莲问题:
你参加一个电视节目,有3个门,其中2个门后是山羊,一个门后是汽车。节目过程是你先挑选一个门,然后主持人会从剩下的两个门中推开一扇藏有山羊的门,然后问你,如果为了赢得汽车,这个时候你是否改变原来的选择。
这个问题也有另一个版本:
有A,B,C三个盒子,已知其中一个装有礼物,另两个是空的,由你随便挑选其中一个而不打开。然后有个知道礼物放在哪个盒子中的人,把另两个盒子中没有礼物的那个打开,现在给你一个换选盒子的机会,即选择另一个剩下的。那么为了使您得到礼物的机会大一些,你选择换还是不换,为什么?
思考
为了方便说明,我选择了第二个对于我来说更方便解释的问题进行说明。首先为了选择,我们需要思考换还是不换的概率是多少。第一次看到这个问题,我直觉上来说是觉得都是二分之一的概率,应该没有差别。但是看到正确答案是选择换的话获奖概率为2/3,不换为1/3以后,我觉得很神奇,同时也产生了想用代码验证的想法。
代码构思
构造模型
首先构造三个盒子的类,我选择用一个长度为三的bool数组模拟三个盒子,利用随机数选择让其中一个为true,其它两个为false
class threeBox {
public:
bool box[3] = {false,false,false}; //先初始三个false
threeBox() { box[rand() % 3] = true;} //随机选择一个box为true
};
好了,构造好了三个box模型,接下来模拟一下第一次选择,利用一个int,保存我们在0-2里面随机的一个数,当作是我们第一次选中的,也就是box的数组下标。完成这些只需要在threeBox类上加上一点点:
class threeBox {
public:
bool box[3] = {false,false,false}; //先初始三个false
int firstSelect; //第一次选择
/*随机一个box为true,然后随机选择一个box当作我们的第一次选择*/
threeBox() { box[rand() % 3] = true; firstSelect = rand() % 3; }
};
到这里其实模型已经构建好了,接下来就是主持人进行选择。为了方便最后的结果显示够直白,我们选择用一个bool函数,返回主持人打开一个空盒子以后剩下的盒子里是有奖还是无奖的(其实机智的朋友这时可能已经反应过来这里才是关键的所在),构造的函数如下:
bool threeBox::change() {
int a[2]; //用来保存剩下的两个盒子的情况
int cnt = 0; //下标
for (int i = 0; i < 3;i++) {
if (i == firstSelect)continue; //如果i等于第一次选择的,则跳过
else a[cnt++] = box[i]; //保存未选择的盒子的状态
}
/*如果两个盒子都为空,则主持人开盒子以后另一个也为空
*则假如我们选择交换,结果是空盒子,所以返回false
*/
if (a[0] == false && a[1] == false) {
return false;
}
/*如果其中一个盒子有奖,则拆另一个盒子
*则我们交换的话就获奖了,返回true
*/
else {
return true;
}
}
测试
测试代码十分简单,直接上代码吧:
int main() {
int cnt = 0; //保存获奖的次数
for (int i = 0; i < 100000; i++) {
threeBox b;
if (b.change() == 1) {
cnt++;
}
else continue;
}
cout << "the probability: " << cnt/1000 << "%" << endl;
system("pause");
return 0;
}
结果
测试结果结果显示结果为66%,其实也就是三分之二。这道题目的正确答案应该是:
- 选择换获奖概率:2/3
- 不换的获奖概率:1/3
我们的测试结果是符合正确答案的。
思考
其实在写交换函数的时候,写到判断的时候就已经知道答案了,因为此时的问题就是剩下的盒子里有无有奖的盒子,有奖的话我们选择换就必中,无奖的话我们选择换就不中。而剩下的两个里面有奖的概率是多少呢?不就是三分之二嘛!所以此时问题就迎刃而解了。我觉得这个问题乍看很摸不着头脑,自己模拟一遍思路就相当开阔了。
最后附上全部代码:
#include<iostream>
#include<random>
using namespace std;
class threeBox {
public:
bool box[3] = {false,false,false};
int firstSelect;
threeBox() { box[rand() % 3] = true; firstSelect = rand() % 3; }
bool change();
};
bool threeBox::change() {
int a[2];
int cnt = 0;
for (int i = 0; i < 3;i++) {
if (i == firstSelect)continue;
else a[cnt++] = box[i];
}
if (a[0] == false && a[1] == false) {
return false;
}
else {
return true;
}
}
int main() {
int cnt = 0;
for (int i = 0; i < 100000; i++) {
threeBox b;
if (b.change() == 1) {
cnt++;
}
else continue;
}
cout << "the probability: " << cnt/1000 << "%" << endl;
system("pause");
return 0;
}