车羊问题(Car and Goats problem)又叫蒙提霍尔问题(Monty Hall Problem)或三门问题。这个问题来源于美国电视娱乐节目Let’s Make a Deal,问题的名字则来自该节目的主持人蒙提·霍尔(Monty Hall)。问题是这样的:参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门就可以赢得该汽车,而另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人会开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。明确的限制条件如下:参赛者会被问是否保持他的原来选择,还是转而选择剩下的那一道 那么换与不换,哪种策略答对的机率高呢?
思考了一下,感觉换的概率可能是1/3,1/2,2/3,无法确定,于是写个程序找到正确答案先:
程序证明
static Random random1 = new Random(); static Random random2 = new Random(); static Random random3 = new Random(); static int COUNT = 100000000; public static void main(String[] args) { //whether re-choise after prompt. boolean retry = true; int got = 0; for (int i = 0; i < COUNT; i++) { int[] data = generateData(); int c = Math.abs(random2.nextInt()) % 3; if (retry) { int p = prompt(data, c); int choise = excluse(c, p); got += data[choise]; } else { got += data[c]; } } System.out.println("retry:" + retry + ",got car:" + got + ",count=" + COUNT + ",probability=" + got * 1.0 / COUNT); } static int excluse(int c, int p) { if (c + p == 1) { return 2; } else if (c + p == 2) { return 1; } else if (c + p == 3) { return 0; } return -1; } static int prompt(int[] data, int c) { int[] choise = new int[2]; int j = 0; for (int i = 0; i < data.length; i++) { if (i != c) { if (data[i] == 1)// car choise[j++] = -1; else choise[j++] = i; } } if (choise[0] >= 0 && choise[1] >= 0) {// c is not car return choise[Math.abs(random3.nextInt()) % 2]; } else if (choise[0] < 0) { return choise[1]; } else { return choise[0]; } } /** * 1 for car,0 for goat */ static int[] generateData() { int[] data = new int[3]; data[Math.abs(random1.nextInt()) % 3] = 1; return data; }
上面的程序,当把retry设成true和false,count设成1亿,得到的输出分别是:
// retry:true,got car:66671490,count=100000000,probability=0.6667149
// retry:false,got car:33331411,count=100000000,probability=0.33331411
从而从程序的角度证明:不换获得车的概率是1/3;换,获得车的概率是2/3.
数学证明
其实用逆推法很容易得出2/3的结论,仔细思考一下,就会发现:
参赛者换了门而且获得了车,当且仅当参赛者第一次选择的门后面是羊。根据等价事件的概率相等的数学原理,问题转换成参赛者第一此选择的门后是羊的概率,也就是2/3.