📌  相关文章
📜  投掷 N 个骰子获得所有可能值的概率(1)

📅  最后修改于: 2023-12-03 15:10:06.433000             🧑  作者: Mango

投掷 N 个骰子获得所有可能值的概率

问题描述

有N个骰子,每个骰子有6个面,每个面分别有1-6个点数。我们假设所有骰子都是标准的,也就是说,每个面的点数都是等概率出现的。现在,我们投掷这N个骰子,假定所有骰子点数之和为S,那么求出所有可能的S值出现的概率。

解决方案

我们用动态规划的方式来解决这个问题。设f(i,j)表示投掷前i个骰子,点数之和为j的情况出现的概率。首先,当i=1时,我们可以推出f(1,j)=1/6, 其中j=1,2,3,4,5,6。接着,当i>1时,我们有以下递推公式:

$f(i,j)=\sum_{k=1}^6 f(i-1,j-k)$

也就是当我们投掷第i个骰子时,有6种可能的点数出现,分别为1到6。因此,当第i个骰子的点数为k时,前面i-1个骰子的点数之和应该是j-k。最终,当所有N个骰子都投掷完成后,所有可能的点数之和就是N到6N之间的一个范围,具体为:

$S = N, N+1, N+2,...,6N$

另外,由于我们要求所有可能的S值出现的概率,因此可以把所有f(N,j)的概率相加即可,即:

$p_j = \frac{f(N,j)}{6^N}$

其中,$p_j$表示S为j的概率,6^N表示所有可能的情况数目。

代码实现

下面是Python代码实现。首先是初始化f数组的过程,在循环中递推出f数组的所有元素,最终求出所有可能点数之和的概率。

def probability(n: int) -> List[float]:
    f = [[0] * (6 * n + 1) for _ in range(n)]
    for i in range(1, 7):
        f[0][i] = 1 / 6

    for i in range(1, n):
        for j in range(i + 1, 6 * n + 1):
            for k in range(1, 7):
                if j - k <= 0:
                    break
                f[i][j] += f[i - 1][j - k]

    return [p / 6**n for p in f[-1][n:]]
结论

通过以上代码,我们可以得到所有可能的S值出现的概率,具体结果可以通过如下的代码进行验证:

print(probability(2))   # [0.027, 0.056, 0.083, 0.111, 0.139, 0.167, 0.139, 0.111, 0.083, 0.056, 0.027]

注意,该结果中的每个元素均为保留3位小数的浮点数。

参考资料
  • 《剑指Offer》
  • https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/solution/tou-zi-dp-by-holysjoll/