期末考试终于结束了!来篇有意思的文章。
最近刷视频的时候刷到了一个彭尼游戏。大致的规则就是两个人每个人都预测一个长度为3的硬币的组合,然后看硬币先满足哪个人的组合,哪个人就获胜。比如A预测硬币组合为正面,正面,正面,B预测硬币组合反面,正面,正面。这时候开始不断抛硬币,直到A和B有一个人猜测的组合和硬币最近三次的结果完全相同,则此人获胜。
乍一看很公平是吧(假设完全不存在假硬币的问题),但是这个游戏最终的结果却令人大跌眼睛:后选择组合的人总是可以比先选择组合的人胜率大。
真的吗?我怎么有点不信呢?鄙人数学一般,但奈何我的算力足够。我们写一个程序来模拟这个游戏不就可以了吗?
项目难度:非常简单;最高级知识点:random库
首先我们先来写输入,接受两个用户输入的组合。此项目中,我们的重点不在这里,干脆就省点时间,不做任何处理,假设用户永远不会捣乱
然后,我们定义一个函数game,它接受两个参数:玩家1的选择,玩家2的选择。然后不断地“抛硬币”,直到有一个人胜利,返回胜利者的编号(1或2)
这个函数整体逻辑比较简单。第18行代码相当于重新抛了一次硬币,然后第19行代码将旧硬币序列集体向右移动,随后将新的结果插入在最左侧。接下来两个if不用我说大家都知道是干啥的
接下来,一次游戏的逻辑已经实现了,让我们直接用这个程序模拟10000次游戏,来看看两人获胜概率是否真的像短视频内说的如此夸张
这个函数仍然没有什么可讲的点,直接开始模拟吧
首先,我们先试试没有技巧的凭自己感觉输入,直觉觉得哪个组合赢得概率大就输入哪个
(这里后来加了一个胜率保留4位小数)
我们可以看到,明明我们感觉胜率差不多,但是大量的实验是不可能骗人的:不可能这10000次测试中randint函数突然出现故障让某个玩家胜率飙升。
关于尼彭游戏有没有通解,或者表格,我上网搜不到,AI给的规律貌似也是错的。这样吧,我们直接来手动探索一下规律
若玩家1输入是100,玩家2输入什么才能让自己胜率最大呢?
略改一下代码,让玩家2有无数次试错机会,然后开始探索
可以看到,对于100组合来说,001的组合是最优的,胜率逼近1:3
既然网上我找不到关于彭尼游戏通解的表格(我**做完这张表格就找到了),那我就自己来做一张最优表格吧!
以上这张表格是我自己用程序整理出来的,绝对准确。左边一栏是玩家一的选择,右边是玩家二的最佳选择,括号内是概率
我们还发现,网络上一些文章说,“对于每一种组合,都有一个方法可以使自己的胜率为对方的三倍。”这是假的。001,010这种无法达到3倍,最多只能两倍,暴力模拟出来的,绝对准确
(均为错误结论↑)
你以为这篇文章就到这里了?不,彭尼游戏只是一个引子而已,我们真正要讲的,是蒙特卡洛思想
蒙特卡洛思想的核心其实特别简单,我们小学就学过。当样本量趋向于无穷大时,目标随机事件出现的概率就接近它在理论上出现的概率
这个思想一开始用在核武器的研究上,随着现在计算机的普及,算力的廉价(至少对于这么点计算量来说的确如此),现在我们遇到概率问题时已经可以“遇事不决,蒙特卡洛”了。
再来几个经典的例子:
有一个多边形,我们怎么求它的面积?
简单,把它用一个矩形框起来,随机生成非常多个(具体数量依据实际情况而定)在矩形内的点坐标,判断点在不在多边形内就可以了(实际上对于不规则多边形这是有一定难度的,但好歹把大问题转化了嘛)。
有一副扑克牌,前五张牌抽到顺子的概率是多少?
简单,用列表模拟牌堆,用random库shuffle洗一下牌。然后直接判断前五张是不是满足递增(或有个特殊的A可以是14也可以是1)即可
(以下代码为AI生成)
以效率慢闻名的(划掉)Python也只用了6秒就算出来了,误差也在可接收范围内
或者我们还可以算一下英语七选五全部蒙错的概率
看到了吗?我们要在什么时候来使用蒙特卡洛思想:
用数学方法求概率相对困难,而判断这个事件是否发生非常简单,且允许一定程度上的误差时,蒙特卡洛便是你非常优秀的选择