基于自定义骰子概率分布,计算100次投掷后登200级以上台阶的概率
计算100次掷骰子后到达200级以上台阶的概率
问题背景
初始位于楼梯底部(0级),掷骰子规则如下:
- 掷出1或2:若不在底部则向下移动1级;若在底部则位置不变
- 掷出3、4、5:向上移动1级
- 掷出6:再次掷骰子,按第二次结果向上移动对应级数(第二次掷骰子同样使用给定的概率分布)
给定骰子6个面的概率分布(如[0.2,0.2,0.2,0.2,0.1,0.1]),需要计算100次投掷后,台阶数≥201的概率。
原代码的问题
你编写的rolldice函数存在两个关键问题:
- 第二次掷骰子(
roll2)没有使用传入的概率分布D,而是用了默认的均匀分布,不符合问题要求 - 每次循环打印
i, Stair会大幅降低模拟效率,不适合大规模重复运行
方法一:蒙特卡洛模拟(近似解)
通过重复运行模拟数千/数万次,统计最终台阶数≥201的次数占总次数的比例,得到近似概率。这是最直观的方法,适合快速得到结果。
优化后的模拟函数
import random def rolldice(T: int, D): stair = 0 for _ in range(T): roll1 = random.choices([1,2,3,4,5,6], weights=D)[0] if roll1 in (1, 2): if stair > 0: stair -= 1 elif roll1 in (3,4,5): stair += 1 elif roll1 == 6: # 第二次掷骰子同样使用给定的分布D roll2 = random.choices([1,2,3,4,5,6], weights=D)[0] stair += roll2 return stair def monte_carlo_probability(num_trials: int, T: int, D): success_count = 0 for _ in range(num_trials): final_stair = rolldice(T, D) if final_stair > 200: success_count += 1 return success_count / num_trials # 示例:运行10000次模拟 prob = monte_carlo_probability(10000, 100, [0.2,0.2,0.2,0.2,0.1,0.1]) print(f"近似概率:{prob:.4f}")
说明
- 模拟次数越多,结果越接近真实概率,通常1万-10万次模拟就能得到足够精确的结果
- 优化后的代码去掉了不必要的打印,合并了条件判断,同时修正了第二次掷骰子的分布问题
方法二:动态规划(精确解)
如果需要精确概率,可以使用动态规划(DP)来计算每个投掷次数下,处于各台阶数的概率。为了减少状态数,我们可以将所有≥201的台阶合并为一个状态(因为我们只关心是否超过200)。
动态规划实现
def dp_probability(T: int, D): # dp[t][s] 表示第t次投掷后,处于s级台阶的概率 # 状态s:0到200,201代表所有≥201的台阶 max_stair = 200 # 初始化:第0次投掷后,处于0级的概率为1 dp_prev = [0.0] * (max_stair + 2) dp_prev[0] = 1.0 for _ in range(T): dp_curr = [0.0] * (max_stair + 2) for s in range(max_stair + 2): if dp_prev[s] == 0: continue # 遍历所有可能的第一次掷骰子结果 for roll1 in range(1,7): p1 = D[roll1-1] if roll1 in (1,2): # 向下移动1级,或停在0级 new_s = max(s - 1, 0) dp_curr[new_s] += dp_prev[s] * p1 elif roll1 in (3,4,5): # 向上移动1级 new_s = s + 1 if new_s > max_stair: new_s = max_stair + 1 dp_curr[new_s] += dp_prev[s] * p1 elif roll1 == 6: # 第二次掷骰子,遍历所有可能结果 for roll2 in range(1,7): p2 = D[roll2-1] new_s = s + roll2 if new_s > max_stair: new_s = max_stair + 1 dp_curr[new_s] += dp_prev[s] * p1 * p2 dp_prev = dp_curr # 最终概率是所有≥201的状态的概率和 return dp_prev[max_stair + 1] # 计算精确概率 prob_exact = dp_probability(100, [0.2,0.2,0.2,0.2,0.1,0.1]) print(f"精确概率:{prob_exact:.6f}")
说明
- 动态规划通过状态转移精确计算每个步骤的概率,没有随机误差
- 将≥201的台阶合并为一个状态,避免了状态数无限增长的问题,计算量可控
内容的提问来源于stack exchange,提问作者Gavin
相关产品推荐
相关产品推荐

