1. 三门问题:当直觉与概率背道而驰

第一次听说三门问题时,我和大多数人一样坚信"换不换都一样"。毕竟主持人打开一扇门后剩下两扇门,看起来概率不就是50%对50%吗?但当我真正用代码模拟了上万次实验后,结果让我大跌眼镜——换门的胜率竟然稳定在66.7%左右,是不换门的两倍!

这个经典问题源自美国电视节目《Let's Make a Deal》,数学家玛丽莲·沃斯·莎凡特在专栏中给出正确答案后,竟然收到了上万封反对信,其中不乏专业数学家。为什么这么简单的问题会引发如此大的争议?关键在于条件概率这个反直觉的概念。就像你玩扑克时,随着牌面逐步揭露,各手牌胜率会动态变化一样,主持人打开门这个动作其实暗中改变了概率分布。

2. 用生活案例拆解概率陷阱

2.1 放大版的"百门游戏"

假设现在不是3扇门而是100扇门,你随机选择1扇后,主持人打开了剩下的98扇空门。这时候你会坚持最初的选择,还是换到剩下的那扇门?显然,最初选对的概率只有1%,而剩下的门有99%的概率包含奖品,即使主持人排除了98个错误选项,最后那扇门仍然继承了原始的高概率。

# 百门问题简化版
import random
doors = ['car'] + ['goat']*99  # 1辆汽车和99只山羊
choice = random.randint(0, 99)  # 随机初始选择
remaining = [i for i in range(100) if i != choice]
opened = random.sample(remaining, 98)  # 打开98扇门
final_choice = [x for x in remaining if x not in opened][0]
# 比较初始选择和最终选择的获奖概率

2.2 扑克牌中的条件概率

想象你从洗好的牌堆中随机抽一张牌,猜它是红桃A的概率是1/52。如果我告诉你这张牌肯定是红桃,概率就变成了1/13。如果再补充说这张牌是A,概率就飙升到1/4。新信息的加入会彻底改变概率分布,这正是三门问题的核心——主持人知道门后情况并刻意打开空门的行为,提供了额外信息量。

3. Python模拟实验全解析

3.1 基础版模拟器搭建

让我们用Python构建一个最基础的三门问题模拟器。关键点在于:

  1. 随机设置汽车位置
  2. 模拟玩家初始选择
  3. 主持人必须打开一扇未被选择且没有汽车的门
  4. 记录换门与不换门的结果
import random
import matplotlib.pyplot as plt

def monty_hall_simulation(trials):
    stay_wins = 0
    switch_wins = 0
    
    for _ in range(trials):
        # 设置奖品位置 (0, 1, 2)
        prize = random.randint(0, 2)
        # 玩家初始选择
        choice = random.randint(0, 2)
        
        # 主持人打开一扇没有奖品的门
        opened = next(i for i in range(3) 
                     if i != choice and i != prize)
        
        # 换门策略选择剩下的门
        switched = next(i for i in range(3) 
                       if i != choice and i != opened)
        
        if choice == prize:
            stay_wins += 1
        if switched == prize:
            switch_wins += 1
    
    return stay_wins, switch_wins

3.2 可视化结果分析

运行10万次模拟后,我们可以用Matplotlib生成直观的对比图表:

trials = 100000
stay, switch = monty_hall_simulation(trials)

labels = ['坚持选择', '更换选择']
win_counts = [stay, switch]
win_percent = [x/trials*100 for x in win_counts]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))
ax1.bar(labels, win_counts, color=['skyblue', 'lightgreen'])
ax1.set_title('获胜次数对比')
ax2.bar(labels, win_percent, color=['skyblue', 'lightgreen'])
ax2.set_title('获胜概率对比 (%)')

for i in range(2):
    ax1.text(i, win_counts[i]+1000, f"{win_counts[i]:,}", ha='center')
    ax2.text(i, win_percent[i]+1, f"{win_percent[i]:.2f}%", ha='center')

plt.tight_layout()
plt.show()

图表会清晰显示换门策略约66%的胜率,完美验证了理论计算。我在第一次跑这个实验时,看到结果曲线逐渐收敛到2:1的比例,那种眼见为实的震撼感至今难忘。

4. 常见误区与深度思考

4.1 主持人的信息量是关键

很多人忽略了一个重要细节:主持人必须打开一扇没有奖品的门。如果主持人随机开门且可能打开汽车门(这时游戏终止),那么换不换门的胜率就真的变成50%了。我们可以修改代码验证这种情况:

def random_host_simulation(trials):
    stay_wins = 0
    switch_wins = 0
    invalid = 0  # 记录主持人意外打开奖品门的情况
    
    for _ in range(trials):
        prize = random.randint(0, 2)
        choice = random.randint(0, 2)
        
        # 主持人随机打开一扇非选择门
        open_options = [i for i in range(3) if i != choice]
        opened = random.choice(open_options)
        
        if opened == prize:  # 主持人打开了奖品门
            invalid += 1
            continue
            
        switched = next(i for i in range(3) 
                       if i != choice and i != opened)
        
        if choice == prize:
            stay_wins += 1
        if switched == prize:
            switch_wins += 1
    
    print(f"无效试验占比: {invalid/trials:.2%}")
    return stay_wins, switch_wins

运行这个版本会发现,在排除无效试验后,两种策略的胜率确实趋近于50%。

4.2 贝叶斯定理的数学解释

从概率论角度看,设:

  • 初始选择正确的概率P(A)=1/3
  • 初始选择错误的概率P(¬A)=2/3

如果初始选择正确(概率1/3),换门必定失败;如果初始选择错误(概率2/3),换门必定成功。因此换门成功的总概率就是初始选错的概率2/3。这可以用贝叶斯定理严格证明:

P(换门获胜) = P(初始选择错误 | 主持人打开空门)
            = P(主持人打开空门 | 初始选择错误) * P(初始选择错误) / P(主持人打开空门)
            = 1 * (2/3) / 1 
            = 2/3

5. 进阶实验与变种问题

5.1 多门扩展实验

我们可以将问题扩展到N扇门,玩家先选1扇,主持人打开K扇没有奖品的门(K≤N-2),然后让玩家决定是否换门。此时:

  • 不换门的胜率:1/N
  • 换门的胜率:(N-1)/N * 1/(N-K-1)

用Python实现这个通用版本:

def generalized_monty_hall(doors, opened_doors, trials=10000):
    stay_wins = 0
    switch_wins = 0
    
    for _ in range(trials):
        prize = random.randint(0, doors-1)
        choice = random.randint(0, doors-1)
        
        # 主持人必须打开指定数量的非奖品门
        open_options = [i for i in range(doors) 
                       if i != choice and i != prize]
        opened = random.sample(open_options, opened_doors)
        
        # 换门策略选择剩下的门
        switch_options = [i for i in range(doors) 
                         if i != choice and i not in opened]
        switched = random.choice(switch_options)
        
        if choice == prize:
            stay_wins += 1
        if switched == prize:
            switch_wins += 1
    
    return stay_wins/trials, switch_wins/trials

测试10门主持人开8门的情况,理论计算换门胜率应该是(9/10)*(1/1)=90%,与模拟结果高度吻合。

5.2 多个参赛者场景

假设现在有两个玩家同时选择不同的门,主持人随后打开一扇两个玩家都没选且没有奖品的门。此时换门策略会怎样?有趣的是,这种情况下两个玩家的最佳策略相反:最初选择顺序靠前的玩家应该坚持,而顺序靠后的玩家应该换门。这个变种很好地展示了条件概率的复杂性。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐