有趣的概率——车羊问题、硬币问题、博弈问题
1、经典车羊问题
假设你参加一个游戏节目,有三扇关闭的门,其中一扇后面有一辆汽车,而其他两扇后面是山羊。你首先选择一扇门,然后主持人打开另外两扇门中的一扇,露出其中一只山羊。
现在,你可以选择是否改变自己的选择,选择另外一扇未被打开的门。那么,应该改变选择还是保持原来的选择呢?
import random def monty_hall_simulation(change_choice, num_trials): wins_times = 0 for _ in range(num_trials): doors = ['car', 'goat', 'goat'] random.shuffle(doors) # 随机排列门的位置 first_selected_door = random.randint(0, 2) # 随机选择一扇门 # 主持人打开一扇有山羊的门 opened_door = next(i for i in range(3) if i != first_selected_door and doors[i] == 'goat')
#判断是否选择交换 if change_choice: selected_door = next(i for i in range(3) if i not in (first_selected_door, opened_door)) else: selected_door = first_selected_door if doors[selected_door] == 'car': wins_times += 1 win_percentage = (wins_times / num_trials) * 100 return win_percentage # 进行10000次实验 win_percentage_with_change= monty_hall_simulation(change_choice=1, num_trials=10000) win_percentage_without_change= monty_hall_simulation(change_choice=0, num_trials=10000) print(f"改变选择时获胜的概率: {win_percentage_with_change}%") print(f"保持选择时获胜的概率: {win_percentage_without_change}%") #输出 改变选择时获胜的概率: 66.25% 保持选择时获胜的概率: 33.22%
2、假如我有初始筹码一百块钱,现在有个抛硬币的游戏,抛出正反面的概率是0.5,每次抛出正面,我的筹码量可以增加80%,抛出反面则减少50%,那么我该玩这个游戏吗?
2.1 如果每次必须all in,则不玩,玩的越多赢钱概率越低,假如每次赢钱增加比例p,每次输钱后亏损比例为q,若(1+p)*(1-q)<1,则不该玩,学过极限的朋友知道,小于1的分数的n次方的极限等于0,有些看起来胜率为0.5的游戏其实是必输的,例如赌场的赌大小,会因为一点点的抽水使得重复n次后变成理论上必输的游戏
def get_res(num_trials): x=100 for _ in range(num_trials): if func_p(0.5) == 1: x=x*1.8 else: x=x*0.5 return x res=get_res(100000) print ("最终收益为:"+str(res-100)) #输出 #最终收益为:-100.0
2.1 如果可以改变筹码量,则可以玩,假如每次赢钱增加比例p,每次输钱后亏损比例为q,虽然(1+p)*(1-q)<1,例如p=0.8,q=0.5,1.8*0.5=0.1<1,因为可以改变筹码量,但是每次赢钱的期望为本金*(p-q)/2 ,只要p>q,就可以玩
#单次抛硬币后我筹码的期望为0.5*180+0.5*50=115,只要有充足的资金,不管玩几次,单次的期望始终为正值
def get_res(num_trials): res=0 for _ in range(num_trials): x=100 #每次筹码量固定 if func_p(0.5) == 1: x=x*1.8 else: x=x*0.5 res=res+x return (res/num_trials) res=get_res(100000) print ("平均收益为:"+str(res-100)) #输出 #平均收益为:15.092299999999994
3、一帅哥在酒吧里喝酒,一美女走来邀请玩游戏,规则是,每人手里拿一个硬币,自己选择正面或者反面,然后扣在桌子上,然后同时把手拿开,如果两个硬币都是正面,美女要给帅哥3块钱,两个都是反面,美女要给帅哥1块钱,如果一正一反,则帅哥要给美女2块钱,男女双方均可以控制自己出正反面的频率,如果你是这个帅哥,你玩吗?
期望看似是E= (1/4)*-3+(1/2)*2+(1/4)*-1 = 0 ,如果两人都是随机出的话,期望确实为0,有没有一种策略,不管帅哥怎么玩,只要他没有读心术,玩多了一定输钱呢?
假设帅哥出正面的频率为X ,出反面的频率为1-X,美女正面的频率为Y ,出反面的频率为1-Y,则帅哥赢钱的期望为 3XY +(-2)*(1-X)*Y+(-2)*(1-Y)*X+(-1)*(1-X)*(1-Y) =8XY-3X-3Y+1。美女如果想让帅哥亏钱,则必须找到一个Y,不管X等于0到1的任何值,使得8XY-3X-3Y+1恒小于0,经计算 1/3<Y<2/5 即可满足条件,即如下图等高线中红框部分
# 激活交互式图形 %matplotlib notebook import numpy as np import matplotlib.pyplot as plt # 定义 x 和 y 的范围 x = np.linspace(0, 1, 100) y = np.linspace(0, 1, 100) # 创建网格点坐标矩阵 X, Y = np.meshgrid(x, y) # 计算相应的 z 值 Z = 8 * X * Y - 3 * X - 3 * Y + 1 # 创建等高线图 plt.contour(X, Y, Z, levels=[0], colors='blue') # 绘制曲面 plt.imshow(Z, extent=(0, 1, 0, 1), origin='lower', cmap='viridis', alpha=0.3) plt.colorbar(label='z') # 设置坐标轴标签 plt.xlabel('x') plt.ylabel('y') # 显示图形 plt.show()
def get_e(x,y,num_trail): l=0 for _ in range(num_trail): res1 = func_p(x) res2 = func_p(y) if res1 == res2 == 1: s=3 elif (res1 == 0 and res2== 1) or (res1 == 1 and res2== 0) : s= -2 elif res1 == res2 == 0: s=1 l=l+s return l res=get_e(0.1,11/30,1000000) print ("玩一百万次后帅哥赢钱为:"+str(res)) #输出 -105832
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?