三门问题也称为蒙提霍尔问题、蒙特霍问题或蒙提霍尔悖论,出自美国的电视游戏节目Let’s make a deal.来自 Craig F. Whitaker 于1990年寄给《展示杂志》(Parade Magazine)玛丽莲·沃斯·莎凡特(Marilyn vos Savant)专栏的信件: “假设你正在参加一个游戏节目,你被要求在三扇门中选择一扇:其中一扇后面有一辆车;其余两扇后面则是山羊。你选择了一道门,假设是一号门,然后知道门后面有什么的主持人,开启了另一扇后面有山羊的门,假设是三号门。他然后问你:“你想选择二号门吗?”转换你的选择对你来说是一种优势吗?”
假设有三个门,选择每个门,门后有车的概率是1/3。
由于主持人知道车所在的门的位置,打开的门后必为羊。
对于选手来说,第一次选择时,门后有车的概率是1/3。而后主持人打开了一扇门,门后没有车。此时事件已经已经发生了改变。
即“你是否换门”
后发生的事情不会影响已经发生的事情的概率,所以门后有车的概率仍然是1/3。无论是否有主持人开门的操作,选手选择换门后能开到有车的门的概率都是2/3
在主持人开门前,有2门共同分享这个概率,故每个门的概率为2/3 * ( 1/ 2 ) = 1/3。主持人开门后,他为你在剩下两个门中排除了一个错误答案,即只有1个门分享这个概率2/3。
所以此时选择剩下的门的概率为2/3。
这样看起来,更像是一个理解的错误。ABC三个门,当你选定一个门A,换门后赢的概率是 2/3 ,只是换门选择的对象有B和C两个,此时
P(换门成功) = P(换门到C成功) + P(换门到B成功)= 2/3
主持人打开门C,里面没有车。P© = 0。所以
P(换门成功) = 0 + P(换门到B成功)
即
P(换门成功) = P(换门到B成功)= 2/3
相似的,当有四个门 A、B、C、D
P(换门成功) = 3/4 = P(B) + P© + 0,所以每个门的概率是3/8
总之,理解这件事需要确定一个前提:后发生的事,不会影响先发生的事件的概率
class ThreeDoor{
private:
int correctDoor;
int doorNum;
map remainDoors;
int selectedDoor = -1;
int deletedDoor = -1;
public:
ThreeDoor(int n) {
doorNum = n;
//随机产生正确的门的数字,填写每个门的概率
correctDoor = ensureCorrectDoor(n);
// remainDoors = new int[n];
for(int i = 0; i < n ; i ++)
remainDoors[i] = 1.0 / n;
}
void startGame();
int ensureCorrectDoor(int n);
void selectDoor();
void deleteDoor();
void retryProbability();
bool isWin = false;
void displayRemain();
void displayGameProcess(int a);
};
inline int ThreeDoor::ensureCorrectDoor(int n) {
//get the correct door
srand(time(0));
//获取一个0-n的随机数
printf("all doors is %d\n",n);
int res = rand() % n;
printf("the correct door is %d\n",res);
return res;
}
开始游戏
inline void ThreeDoor::startGame() {
for(int i = 0; i < remainDoors.size(); i++){
//显示进度
displayGameProcess(i);
//仅有两个门的时候显示结果
if(doorNum <= 2) break;
//只有前两轮进行换门操作
if(i < 2) selectDoor();
//主持人进行排查操作
deleteDoor();
retryProbability();
}
if(selectedDoor != correctDoor) {
printf(" you win!!!!!!!\n");
isWin = true;
}
else
printf(" you lose!!!!!!!\n");
}
在大概率的几个选项中,选择一个门
bool cmp(pair a , pair b) {
return a.second > b.second;
}
inline void ThreeDoor::selectDoor() {
printf("\n\n start to select doors........\n");
//change to vector and sort according probability ASC (from big to small)
vector> doorVect(remainDoors.begin(),remainDoors.end());
sort(doorVect.begin(),doorVect.end(),cmp);
//get all max probability, and selected one
vector>::iterator iter = doorVect.begin();
float max = doorVect.begin()->second;
printf("\t get the max probability \t%f\n",max);
while (iter != doorVect.end()) {
// printf("[%d,%f]\t",iter->first,iter->second);
if(max > iter->second) {
// printf("\n current probability is %f , max probability is %f\n",iter->second,max);
iter --;
break;
}
iter++;
}
// cout << endl;
int num = iter - doorVect.begin();
printf("\t probability \t num \n");
printf("\t %f \t %d \n",max,num);
int tmp;
do {
// printf("all door num is %d doorNum = %d\n",num,doorNum);
tmp = rand() % num;
// printf("the selected number is : %d all door num is %d doorNum = %d\n",tmp,num,doorNum);
} while(remainDoors[doorVect[tmp].first]== 0);
selectedDoor = doorVect[tmp].first;
printf("\t get the selected door is \t%d\n",doorVect[tmp].first);
cout << endl;
}
主持人排除一个门
inline void ThreeDoor::deleteDoor() {
//这个部分删除操作是随机的,随机选择剩下门中的任何一个
printf(" start to delete doors........\n");
printf("\t the num can be deleted \t %d\n",doorNum);
int tmp;
printf("\t the door doors : \t");
do {
tmp = rand() % remainDoors.size();
printf("%d ",tmp);
} while(remainDoors[tmp]== 0 || tmp == selectedDoor || tmp == correctDoor);
printf("\n");
printf("\t get the deleted door is \t%d\n",tmp);
//此处是手动控制需要排除的门
// do {
// printf("input the door to be deleted : ");
// scanf("%d",&tmp);
// printf("\n");
// } while (tmp == selectedDoor || remainDoors[tmp] == 0 || tmp > remainDoors.size() || tmp < 0);
remainDoors[tmp] = 0;
doorNum -= 1;
deletedDoor = tmp;
displayRemain();
}
重新计算概率
inline void ThreeDoor::retryProbability() {
printf(" start to caculate probability........\n");
float prob = (1.0 - remainDoors[selectedDoor]) / (doorNum - 1 );
printf("\t selectedProb \t remainProbe \t remainDoor \t result\n");
printf("\t %f \t %f \t %d \t %d \n",
remainDoors[selectedDoor],(1.0 - remainDoors[selectedDoor]),doorNum,prob);
printf("the probability is %f",prob);
for(int i = 0; i < remainDoors.size();i++) {
if(remainDoors[i] == 0 || i == selectedDoor) continue;
remainDoors[i] = prob;
}
}