三门问题的解释和程序验证

一个游戏:有3扇关闭着的门,其中2扇门后面各有一只羊,另一扇门后面有一辆车。
参与者:一个游戏者和一个主持人。主持人事先知道各扇门后的物品,而游戏者不知道。
游戏目的:游戏者选择到车。
游戏过程:1、游戏者随机选定一扇门;2、在不打开此扇门的情况下,主持人打开另一扇有羊的门。3、此时面对剩下2扇门,游戏者有一次更改上次选择的机会。
问题:游戏者是否应该改变上次的选择,以使选到车的概率较大?

问题的学名叫《蒙提霍尔问题》,阅读原文有来龙去脉。

答案有换和不换两种,有的认为是换概率是2/3,有的认为是不换和换都一样,概率是50%,因为后面剩两个概率是相同的。

正确答案是应该换,几种解释:

  1. 游戏者坚持每次都换,开始选中羊的概率是2/3, 在第一次选中羊的情况下,换了就能够得到车,所以换能得到车的概率是2/3。
  2. 假设有1000个门,只有一个后面有车,如果主持人帮游戏者打开选后的998个门,要不要换?当然换,排除了错误答案的情况,换的概率会高很多。

除了思考的方式,还可以写个程序,用实验的方式验证。(在一些不容易想的问题上,可以用程序模拟多次独立事件,直观查看结果,但不一定和理论完全一样)

代码和结果如下,如果在主持人提示后换的话,也是2/3的概率选中车。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"

#define DOOR_COUNT 3
int getrand( int max )
{
    double max_rand = RAND_MAX * 1.0;
    return (rand() /max_rand) * max;
}
int choose( int changed )
{
    char door[ DOOR_COUNT ] = { 0 };
    int moto_index = getrand( DOOR_COUNT );//车子所在的门序号
    door[ moto_index ] = 1;
    int choose_index = getrand( DOOR_COUNT );//游戏者第一次选的门序号
    int left_index = -1;
    int display_index = -1;
    int i;
    for (i = 0; i < DOOR_COUNT; i++) {
        if( i == choose_index  )
            continue;
        if( i == moto_index )
            continue;
        display_index = i;//主持人打开的门序号
        break;
    }
    for( i=0; i < DOOR_COUNT; ++i )
    {
        if( i == choose_index  )
            continue;
        if( i == display_index )
            continue;
        left_index = i;//最后没打开的门序号
    }
    printf("moto_index = %d first_choose_index = %d display_index = %d left_index = %d\n",
            moto_index, choose_index, display_index, left_index);
    if( changed == 1)
        choose_index = left_index;
    if( choose_index == moto_index )
        return 1;
    return 0;
}
int main(int argc, const char *argv[])
{
    srand( ( unsigned  )time( NULL ) );
    int count = 10000;
    int changed = 1;//交换
    int motocount = 0;
    int i;
    for (i = 0; i < count; i++) {
        int iRet = choose( changed );
        motocount += iRet;
    }
    printf( "changed = %d count = %d motocount = %d, rate = %0.2f\n",
            changed, count, motocount, motocount*1.0/count);
    system( "pause" );
    return 0;
}

运行结果

moto_index = 0 first_choose_index = 1 display_index = 2 left_index = 0
moto_index = 2 first_choose_index = 2 display_index = 0 left_index = 1
moto_index = 1 first_choose_index = 2 display_index = 0 left_index = 1
......
moto_index = 2 first_choose_index = 0 display_index = 1 left_index = 2
moto_index = 2 first_choose_index = 0 display_index = 1 left_index = 2
moto_index = 0 first_choose_index = 0 display_index = 1 left_index = 2
moto_index = 1 first_choose_index = 0 display_index = 2 left_index = 1
moto_index = 2 first_choose_index = 0 display_index = 1 left_index = 2
moto_index = 0 first_choose_index = 1 display_index = 2 left_index = 0
moto_index = 1 first_choose_index = 0 display_index = 2 left_index = 1
moto_index = 0 first_choose_index = 2 display_index = 1 left_index = 0
moto_index = 2 first_choose_index = 1 display_index = 0 left_index = 2
moto_index = 0 first_choose_index = 2 display_index = 1 left_index = 0
changed = 1 count = 10000 motocount = 6692, rate = 0.67

转载请注明来源:三门问题的解释和程序验证
欢迎收听公众号

发表评论

电子邮件地址不会被公开。 必填项已用*标注