车与羊的选择

通过电影《决胜21点》中的一个场景引入蒙提霍尔问题,并使用Java编程模拟实验证明了更换选择会显著提高胜率,揭示了这一反直觉的概率论现象。
电影《决胜21点》开始部分,课堂上教授问了这样一个问题:
假设你正在参加一个电视游戏节目,被要求在三扇门中选择一扇。其中一扇后面有一辆车,其余两扇后面则是羊。你选择了一扇门,假设是1号门。这时候不知什么原因,主持人——他知道各个门后面都有什么——却开启了另一扇门,假设是3号门,后面是羊。然后他问你:“现在给你一个改变主意的机会,你想换成2号门吗?”

剧中的学霸男主立刻回答:“当然应该换,原来选一号门时有1/3的概率得到车,换的话则会有2/3的概率。”教授说:“Exactly!” 。


看到这我不禁吃了一惊 ,这个答案有点反常识么,我的想法是:因为3号门已经被排除,剩下两扇门有车的概率是一半对一半,换不换应该无所谓才对。

究竟电影是在戏说,还是我的直觉错了,毕竟当初没有好好学过概率论,遇到这种问题总是犯迷糊,不过所谓实践出真知,我们也许可以实际测试一下,当然不可能在真实世界进行测试,还是用程序来仿真吧:


设有一个长度为3的布尔数组,每个元素代表1扇门,元素下标代表门的序号。元素值为真表示门后为车,值为假表示门后为羊。
创建两个线程分别代表主持人和玩家,主持人线程的流程为:
1)开始,随机设定某一数组元素为真,其余为假。然后唤醒玩家线程
2)将自己挂起
3)(在玩家选择了一个元素后被唤醒),从剩下的两个元素中选出一个为假的元素,记下其序号(表示排除这扇门)。然后唤醒玩家线程
4)将自己挂起
5)被唤醒后回到1)
玩家线程的流程为:
1)开始,将自己挂起
2)(在主持人设定数组后被唤醒),随机选择一个元素,记下其序号。然后唤醒主持人线程
3)将自己挂起
4)(在主持人标记一个为假的元素后被唤醒),如果不需要换门,则保持自己在2)中选择的原序号不变。如果需要换门,则更新序号,使新序号既不等于原序号,也不等于主持人在3)中排除的序号。然后检查选中序号所指元素的值,如为真则表示命中了车,为假表示命中了羊。然后唤醒主持人线程

5)回到第一步


另外,我用两个外部参数分别控制游戏进行的次数和玩家线程在4)中是否需要换门。设游戏次数为一千次,按不换门和换门分别进行测试,输出到控制台的结果大致是这样:

>>>>>>
$ java tmp.SheepOrCar


Test01: 1000 times without change
Result: Total(1000)Cars(318)Rate(%31)


Test02: 1000 times with change
Result: Total(1000)Cars(682)Rate(%68)
<<<<<<

在各1000次游戏中,坚持不换门的命中汽车318次,命中率31%,换门的命中682次,命中率68%,似乎已足以说明问题了。所以学霸毕竟是学霸,而我的直觉是靠不住的。
我的测试代码在:
https://github.com/sunxiaoou/TIJ4/blob/master/tmp/SheepOrCar.java
这里是一个简单的山轿选择游戏的 MATLAB 代码示例: ```matlab % 游戏开始 fprintf('欢迎来到山轿选择游戏!\n\n'); % 初始化游戏参数 n = 100; % 游戏次数 win_car = 0; % 选择赢的次数 win_goat = 0; % 选择赢的次数 % 开始游戏 for i = 1:n % 随机选择一个门放置奖品 prize = randi(3); % 玩家选择一个门 choice = randi(3); fprintf('第 %d 次游戏,您选择了第 %d 号门\n', i, choice); % 主持人打开另外一扇门,露出山 goat = setdiff(1:3, [prize, choice]); shown = goat(randi(2)); fprintf('主持人打开了第 %d 号门,露出了一只山\n', shown); % 玩家是否要更换选择 change = randi(2)-1; % 随机 0/1 if change % 如果玩家更换选择,则选择除了已选门和已打开门以外的另一扇门 choice = setdiff(1:3, [choice, shown]); fprintf('您更换了选择选择了第 %d 号门\n', choice); end % 判断是否获胜 if choice == prize fprintf('恭喜您获得了一辆!\n'); win_car = win_car + 1; else fprintf('很遗憾,您只获得了一只山\n'); win_goat = win_goat + 1; end fprintf('\n'); end % 显示游戏结果 fprintf('游戏结束,您一共玩了 %d 次\n', n); fprintf('选择获胜的次数为 %d 次,占比 %.2f%%\n', win_car, win_car/n*100); fprintf('选择获胜的次数为 %d 次,占比 %.2f%%\n', win_goat, win_goat/n*100); ``` 游戏规则: 1. 主持人有三扇门,其中一扇门后面有一辆,另外两扇门后面是山。 2. 玩家随机选择一扇门。 3. 主持人会打开另外一扇门,露出一只山。 4. 玩家可以选择更换选择或者保持原来选择。 5. 如果玩家选择的门后面是,则获胜;否则获得的是一只山。 在代码中,我们通过循环运行游戏 100 次,统计选择选择获胜的次数,最后输出游戏结果。在每次游戏中,我们使用 `randi` 函数随机生成门和奖品的位置,使用 `setdiff` 函数排除已选门和已打开门,得到玩家可以选择的门。最后,根据玩家的选择和奖品位置,判断是否获胜。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值