三门问题

    29

简介

三门问题(Monty Hall Problem)是一个著名的概率论问题,它源于美国的一档电视游戏节目。问题的描述如下:

有三扇门,其中一扇门后面有一辆汽车,另外两扇门后面则是山羊。

参赛者选择一扇门,希望能赢得汽车。

主持人(Monty Hall)知道每扇门后面的奖品,他会打开剩下的两扇门中的一扇,露出一只山羊。

此时,主持人会给参赛者一个选择:坚持原来的选择,还是换到另一扇未打开的门。

问题是:参赛者应该坚持原来的选择,还是换到另一扇门,或者说两种策略都无所谓?

反直觉之处

根据概率论,参赛者更换门的策略胜率更高。

更换门的策略胜率为2/3

而坚持原来选择的策略胜率为1/3。

如果此时另一位参赛者入场,在这两个门中选其中一个,两个门的概率是1/2。

这个结论可能违反直觉,但可以通过条件概率和贝叶斯定理来解释。

当主持人打开一扇门后,参赛者的信息发生了变化。原本,每扇门背后有汽车的概率都是1/3。但在主持人打开一扇门后,剩下的两扇门中,一扇门背后有汽车的概率变为了1/2。然而,由于主持人总是打开一扇有山羊的门,这意味着如果参赛者最初选择了山羊(2/3的概率),那么更换门后就会赢得汽车;而如果参赛者最初选择了汽车(1/3的概率),更换门后就会得到山羊。因此,更换门的策略胜率为2/3。

程序分析

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 1000 //测试次数

int main()
{
srand(time(NULL)); //设置随机数种子
int ball = 0; //汽车所在的门的编号
int choice = 0; //参赛者选择的门的编号
int open = 0; //主持人打开的门的编号
int switch_win = 0; //更换门后赢得汽车的次数
int stay_win = 0; //保持原选择后赢得汽车的次数
for (int i = 0; i < N; i++) //循环测试N次
{
ball = rand() % 3 + 1; //随机生成汽车所在的门编号,1到3之间
choice = rand() % 3 + 1; //随机生成参赛者选择的门编号,1到3之间
open = rand() % 3 + 1;
do //确保主持人打开的不是参赛者选择,也不是有车的门。
{
open = rand() % 3 + 1; //随机生成主持人打开的门编号,1到3之间
} while (open == ball || open == choice); //
if (choice == ball) //如果参赛者选择的门就是汽车所在的门
{
stay_win++; //保持原选择后赢得汽车的次数加一
}
else //如果参赛者选择的门不是汽车所在的门
{
switch_win++; //更换门后赢得汽车的次数加一
}
}
printf("更换门后赢得汽车的次数:%d\n", switch_win); //输出更换门后赢得汽车的次数
printf("保持原选择后赢得汽车的次数:%d\n", stay_win); //输出保持原选择后赢得汽车的次数
return 0;
}

输出:

更换门后赢得汽车的次数:662 
保持原选择后赢得汽车的次数:338

个人分析

3个门感受还是不太直观,假设:

有100个杯子,其中一个有球

参赛者选择其中一个杯子

主持人打开其余的98个空杯子,只剩下最后两个杯子,其中一个有球。

此时保持原来选择的中奖率为1/100

而改变选择的中奖率为99/100

循环1000次结果如下:

分析验证

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 1000 //测试次数
#define M 100 //杯子数量

int main()
{
    srand(time(NULL)); //设置随机数种子
    int ball = 0; //小球所在的杯子编号
    int choice = 0; //参赛者选择的杯子编号
    int open = 0; //主持人打开的杯子编号
    int switch_win = 0; //更换杯子后赢得小球的次数
    int stay_win = 0; //保持原选择后赢得小球的次数
    for (int i = 0; i < N; i++) //循环测试N次
    {
        ball = rand() % M + 1; //随机生成小球所在的杯子编号,1到M之间
        choice = rand() % M + 1; //随机生成参赛者选择的杯子编号,1到M之间
        for (int j = 0; j < M - 2; j++) //主持人打开M - 2个空杯子
        {
            do
            {
                open = rand() % M + 1; //随机生成主持人打开的杯子编号,1到M之间
            } while (open == ball || open == choice); //确保主持人打开的杯子既不是小球所在的杯子,也不是参赛者选择的杯子
        }
        if (choice == ball) //如果参赛者选择的杯子就是小球所在的杯子
        {
            stay_win++; //保持原选择后赢得小球的次数加一
        }
        else //如果参赛者选择的杯子不是小球所在的杯子
        {
            switch_win++; //更换杯子后赢得小球的次数加一
        }
    }
    printf("更换杯子后赢得小球的次数:%d\n", switch_win); //输出更换杯子后赢得小球的次数
    printf("保持原选择后赢得小球的次数:%d\n", stay_win); //输出保持原选择后赢得小球的次数
    return 0;
}

输出

更换杯子后赢得小球的次数:991 
保持原选择后赢得小球的次数:9

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息