蒙提霍尔问题

蒙提霍尔问题(Monty Hall problem),亦称为三门问题,有可能是历史上最富争议的概率问题。蒙提·霍尔是美国电视游戏节目 Let's Make a Deal 的主持人,蒙提霍尔问题就是源自该节目中的一个游戏。

這个游戏的玩法是:参赛者会看见三扇关闭的门,其中一扇门的后面有汽车,选中后面有汽车的那扇门就可以贏得该汽车。而另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,知道门后情形的节目主持人会开启剩下两扇门中的一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。

问题是:换另一扇门是否会增加参赛者贏得汽车的概率?

这个问题也被叫做蒙提霍尔悖论:虽然该问题的答案在逻辑上并不自相矛盾,但十分违反直觉。这个问题曾引起热烈的讨论。

明确的限制条件

Mueser 和 Granberg 为主持人的行为加上明确的限制条件,提出了对这个问题的一种不含糊的陈述:

  • 参赛者在三扇门中挑选一扇。他并不知道门后是什么。
  • 主持人知道每扇门后面有什么。
  • 主持人必须开启剩下两扇门中的一扇,并且必须给参赛者提供换门的机会。
  • 主持人永远都会开启一扇有山羊的门。
    • 如果参赛者挑选了一扇有山羊的门,主持人必須开启另一扇有山羊的门。
    • 如果参赛者挑选了一扇有汽车的门,主持人随机开启另外两扇有山羊的门中的一扇。
  • 参赛者会被问是否保持他的原来的选择,还是转而选择剩下的那一扇门。

改变选择可以增加参赛者赢得汽车的概率吗?

计算机模拟程序

根据以上论述,我们有以下 C# 程序:

 1: using System;
 2: 
 3: namespace Skyiv.Ben.MontyHallProblem
 4: {
 5:   sealed class Game
 6:   {
 7:     // 以下三个变量的取值范围均为 0,1,2 。
 8:     int car;    // 汽车在哪扇门后面?
 9:     int choice; // 参赛者选择了哪扇门?
10:     int shown;  // 主持人开启了哪扇门?
11:     
12:     public Game(Random rand)
13:     {
14:       // Random.Next(3) 随机返回 0,1,2 中的一个。
15:       car = rand.Next(3);     // 随机安排汽车在某一扇门后面。
16:       choice = rand.Next(3);  // 参赛者在三扇门中随机挑选一扇。
17:       shown = GetShown(rand); // 主持人开启一扇有山羊的门。
18:     }
19:     
20:     int GetShown(Random rand)
21:     {
22:       // 参赛者挑选了一扇有山羊的门,主持人开启另一扇有山羊的门。
23:       if (car != choice) return GetRemainDoor(choice, car);
24:       
25:       // 参赛者挑选了一扇有汽车的门,主持人随机开启另外两扇有山羊的门中的一扇。
26:       var r = rand.Next(2); // Random.Next(2) 随机返回 0,1 中的一个。
27:       if (choice == 2) return r;     // 如果参赛者挑选了2号门,主持人随机开启 0,1 号门中的一扇。
28:       if (choice == 0) return r + 1; // 如果参赛者挑选了0号门,主持人随机开启 1,2 号门中的一扇。
29:       return r * 2;                  // 如果参赛者挑选了1号门,主持人随机开启 0,2 号门中的一扇。
30:     }
31:     
32:     int GetRemainDoor(int a, int b)
33:     { // 返回 a 和 b 以外的另一扇门。a, b 和返回值的取值范围均为 0,1,2,且 a != b 。
34:       return 3 - a - b;
35:     }
36:     
37:     public bool StickerWin()
38:     { // 保持选择,参赛者选中有汽车的门就赢了。
39:       return car == choice;
40:     }
41:     
42:     public bool SwapperWin()
43:     { // 改变选择,参赛者新的选择是另一扇尚未开启的门。
44:       return car == GetRemainDoor(choice, shown);
45:     }
46:   }
47: 
48:   sealed class Tester
49:   {
50:     static void Main()
51:     {
52:       var rand = new Random();
53:       int n = 100000000, stickers = 0, swappers = 0;
54:       for (var i = 0; i < n; i++)
55:       {
56:         var game = new Game(rand);
57:         if (game.StickerWin()) stickers++;
58:         if (game.SwapperWin()) swappers++;
59:       }
60:       Console.WriteLine("测试次数: {0:N0}", n);
61:       Console.WriteLine("保持选择:  {0:N0} ({1:P})", stickers, stickers / (double)n);
62:       Console.WriteLine("改变选择:  {0:N0} ({1:P})", swappers, swappers / (double)n);
63:     }
64:   }
65: }

上述程序模拟玩这个游戏一亿次,计算在保持选择和改变选择两种情况下赢得汽车的概率。

运行结果

在 Arch Linux 64-bit 操作系统 Mono 3.4.0 环境下编译和运行:

$ dmcs MontyHallProblem.cs
$ mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,337,906 (33.34%)
改变选择: 66,662,094 (66.66%)
$ mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,339,359 (33.34%)
改变选择: 66,660,641 (66.66%)
$ mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,327,813 (33.33%)
改变选择: 66,672,187 (66.67%)
$ mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,330,327 (33.33%)
改变选择: 66,669,673 (66.67%)
$ mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,337,882 (33.34%)
改变选择: 66,662,118 (66.66%)

从上面五次运行结果看,保持选择赢得汽车的概率是 1/3,而改变选择赢得汽车的概率是 2/3

如果主持人不知道奖品在哪里

《统计思维:程序员数学之概率统计》第 5 章第 2 节“蒙提霍尔问题”的最后:

习题5-5

理解蒙提霍尔问题的重点在于要明白蒙提打开一扇门实际上是给你提供了信息。想象一下,如果蒙提不知道奖品在哪里,随机打开B门或C门,会怎么样?

如果打开的门后是汽车,游戏结束,你输了,再没有选择的机会。否则,你是应该坚持还是改变选择?

要解这道题,只要删除上述 C# 程序第 22 至 25 行,重新编译和运行:

$ dmcs MontyHallProblem.cs && mono MontyHallProblem.exe
测试次数: 100,000,000
保持选择: 33,335,483 (33.34%)
改变选择: 33,330,986 (33.33%)

可见在此情况下,坚持和改变选择是一样的,都只有 1/3 的概率赢得奖品。

参考资料

参考资料[1]提供了详细全面的内容。参考资料[3]的评论很值得一看。

  1. Wikipedia: Monty Hall problem
  2. Rosetta Code: Monty Hall problem
  3. 图灵社区:有趣的概率问题——你是那个打死都不相信正确答案的人吗?
  4. 图灵社区:统计思维:程序员数学之概率统计:5.2 蒙提霍尔问题

Book849