文章目录
题目描述
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
示例 1:
输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
示例 2:
输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
解题前须知:
- 投掷 n 个骰子,一共会有 6 的 n 次方种结果,且每种结果都是等可能事件。
- 投掷 n 个骰子,那么就会有 n 个面朝上,这 n 个朝上的面的点数之和 s 的最大值是 6n,最小值是 n。故投掷 n 个骰子,s 一共有 6n - n + 1 个可能的值(所以题目所要我们返回的浮点数组的大小就是 n * 6 - n + 1。
- s 的每一个可能值的概率等于:这个值出现的次数(可表示为 #s,即 the number of s) / 6 的 n 次方。之所以可以这么计算,是因为所有事件都是等可能事件。所以最终需要返回的浮点数组的内容就会是这个样子:
[#n / pow(6.0, n), #(n + 1) / pow(6.0, n), #(n + 2) / pow(6.0, n), ..., #6n / pow(6.0, n)]。
题解思路
-
我们先建立二维 dp 数组,dp[n][s] 表示投掷 n 个骰子,n 个朝上的面的点数之和为 s 的事件出现的次数。
-
那么动态转移方程就是:dp[n][s] += dp[n - 1][s - k],k 属于 [1, 6]。
- 举个例子来理解,假如 n = 3, s = 8,那么 dp[3][8] 表示投掷 3 个骰子,3 个朝上的面的点数之和为 8 的事件出现的次数。那么我们可以把求 dp[3][8] 转移为求只投掷 2 个骰子,2 个朝上的面的点数之和分别为 7、6、5、4、3、2 的事件的次数之和。
- 因为假如 “只投掷 2 个骰子,2 个朝上的面的点数之和为 7”,那么我们只需要再投一个骰子,让它的点数是 1,不就满足了 dp[3][8] 了嘛!
- 又比如 “只投掷 2 个骰子,2 个朝上的面的点数之和为 6”,那么我们只需要再投一个骰子,让它的点数是 2,不就满足了 dp[3][8] 了嘛!
- 因为我们投一个骰子,它的点数只有可能是 1 到 6,所以我们让前面 n - 1 个骰子的点数和为 s - k,k 属于 [1, 6],我们就能再投一个骰子,然后用这个骰子的点数弥补进前 n - 1 个骰子的点数和,从而得到 s。
-
当然,上面的动态转移方程的前提条件是要保证 s - k > 0,因为没有骰子能投掷出小于等于 0 的点数。
dp 数组初始化
- 首先为了方便表达,我们将 dp 数组的行的数量设为 n + 1,列的数量设为 6n + 1。行表示 n,列表示 s,且 s 的最大值是 6n。
- 首先假如只有一个骰子(n = 1),s 的范围是 [n, 6n],所以 s 的范围是 [1, 6],且 s 的每个值可能出现的次数都为 1。
代码生成:
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<double> res(n * 6 - n + 1);
vector<vector<int>> dp(n + 1, vector<int>(6 * n + 1, 0)); // 将全部值初始化为 0
int row = dp.size(), col = dp[0].size();
for(int n = 1; n <= 6; ++n){
dp[1][n] = 1; // 初始化 dp 数组
}
for (int n = 2; n < row; ++n) {
for (int s = n; s < col; ++s) {
// 注意 s 从 n 开始,因为 s 的最小值为 n
// 比如掷 3 个骰子,s 最小为 3
for (int k = 1; k <= 6; ++k) {
if (s - k > 0) {
dp[n][s] += dp[n - 1][s - k];
}
else {
break;
}
}
}
}
double deno = pow(6.0, n); // 分母
for (int s = n; s <= 6 * n; ++s) {
// s 的最小值为 n,在 res 里是第 s - n 位
res[s - n] = dp[n][s] / deno;
}
return res;
}
};
如有帮助到您,可以多多点赞、评论鼓励哟~~~