摇骰子的胜利概率 | 豆包MarsCode AI 刷题

172 阅读4分钟

问题描述

小U和小S分别拥有不同面数的骰子,每个骰子的面数不同,摇到每一面的概率均等。两人同时摇各自的骰子,并将摇出的点数相加,得分较高的一方获胜,得分相同则为平局。我们需要计算小U获胜的概率。

关键点

  1. 骰子的面数:每个骰子的面数不同,范围在1到k之间。
  2. 概率均等:每个面出现的概率是 1/a_i 或 1/b_j
  3. 得分计算:两人分别摇骰子,并将点数相加,得分较高的一方获胜。

解题思路

1. 理解问题

我们需要计算小U获胜的概率。为了做到这一点,我们需要知道两人所有可能的得分组合,并计算小U得分高于小S的概率。

2. 数据结构选择

  • 动态规划:使用动态规划来计算每个骰子组合的得分概率分布。
  • 概率分布:计算每个可能得分出现的概率,然后通过概率分布来计算获胜的概率。

3. 算法步骤

  1. 计算小U的得分概率分布

    • 初始化一个数组 u_prob_dist,表示小U所有可能得分的概率分布。
    • 对于每个骰子,更新 u_prob_dist,计算新的得分概率分布。
  2. 计算小S的得分概率分布

    • 初始化一个数组 s_prob_dist,表示小S所有可能得分的概率分布。
    • 对于每个骰子,更新 s_prob_dist,计算新的得分概率分布。
  3. 计算小U获胜的概率

    • 遍历小U的所有可能得分和小S的所有可能得分,计算小U得分高于小S的概率。

动态规划计算得分概率分布

假设小U有两个骰子,面数分别为 a1 和 a2,我们可以通过动态规划来计算所有可能得分的概率分布。

  1. 初始状态u_prob_dist = [1],表示只有一个得分0的概率为1。

  2. 第一个骰子:假设 a1 = 3,更新 u_prob_dist

    • 新的得分概率分布为 [1/3, 1/3, 1/3]
  3. 第二个骰子:假设 a2 = 4,更新 u_prob_dist

    • 新的得分概率分布为 [1/12, 1/6, 1/4, 1/6, 1/12]

计算获胜概率

遍历小U和小S的所有可能得分,计算小U得分高于小S的概率。

代码详解


def solution(n, m, arrayN, arrayM):
    # 计算小U所有可能得分的概率分布
    u_prob_dist = [1]  # 初始概率分布,只有一个得分0的概率为1
    for a in arrayN:
        new_prob_dist = [0] * (len(u_prob_dist) + a - 1)
        for score, prob in enumerate(u_prob_dist):
            for face in range(1, a + 1):
                new_prob_dist[score + face] += prob / a
        u_prob_dist = new_prob_dist
    
    # 计算小S所有可能得分的概率分布
    s_prob_dist = [1]  # 初始概率分布,只有一个得分0的概率为1
    for b in arrayM:
        new_prob_dist = [0] * (len(s_prob_dist) + b - 1)
        for score, prob in enumerate(s_prob_dist):
            for face in range(1, b + 1):
                new_prob_dist[score + face] += prob / b
        s_prob_dist = new_prob_dist
    
    # 计算小U获胜的概率
    u_wins = 0
    for u_score, u_prob in enumerate(u_prob_dist):
        for s_score, s_prob in enumerate(s_prob_dist):
            if u_score > s_score:
                u_wins += u_prob * s_prob
    
    return round(u_wins, 3)

if __name__ == "__main__":
    # Add your test cases here
    print(solution(1, 3, [8], [2, 3, 4]) == 0.255)

代码解释

  1. 初始化概率分布

    • u_prob_dist = [1] 和 s_prob_dist = [1] 表示初始状态下只有一个得分0的概率为1。
  2. 动态规划更新概率分布

    • 对于每个骰子,更新概率分布数组,计算新的得分概率分布。
  3. 计算获胜概率

    • 遍历小U和小S的所有可能得分,计算小U得分高于小S的概率。

总结

在实现这个计算小U获胜概率的程序过程中,我深刻体会到了动态规划在解决这类问题中的强大能力。通过构建得分概率分布,我们能够有效地避免了暴力解法中的重复计算,显著提高了算法的效率。