题目描述
把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]
限制:
1 <= n <= 11
题解
题解1: 动态规划
动态规划三步曲:
- 状态表示
dp[n][s]表示n个骰子,n 个朝上的面的点数之和为 s 的事件出现的次数。 - 转移方程
dp[n][s] += dp[n - 1][s - k],k 属于 [1, 6]。当前状态只能由前一状态转移而来. - 初始化
投一个骰子只能有6种不同情况,其他状态都是由一个骰子的状态转移而来
for (int s = 1; s <= 6; ++s) {
// 初始化 dp 数组
dp[1][s] = 1;
}
整体代码如下:
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<double> res;
vector<vector<int> > dp(n + 1, vector<int>(6 * n + 1, 0)); //将全部值初始化为 0
// dp[n][s]表示n个骰子,n 个朝上的面的点数之和为 s 的事件出现的次数。
int row = dp.size(), col = dp[0].size();
for (int s = 1; s <= 6; ++s) {
// 初始化 dp 数组
dp[1][s] = 1;
}
for (int n = 2; n < row; ++n) {
for (int s = n; s < col; ++s) {
for (int k = 1; k <= 6; ++k) {
if (s - k >= n-1) {//n-1个骰子点数和最小为n-1
dp[n][s] += dp[n - 1][s - k];
} else {
break;
}
}
}
}
double denominator = pow(6.0, n); // 分母
for (int s = n; s <= 6 * n; ++s) {
res.push_back(dp[n][s] / denominator);
}
return res;
}
};
题解2: 动态规划(状态压缩)
由于每个阶段(骰子数n)的状态都只和它前一阶段(点数s-1)的状态有关,因此我们不需要用额外的一维来保存所有阶段。
用一维数组来保存一个阶段的状态,然后对下一个阶段可能出现的点数 s 从大到小遍历,实现一个阶段到下一阶段的转换。
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<double> res;
vector<int> dp(6 * n + 1, 0); //将全部值初始化为 0
// dp[n][s]表示n个骰子,n 个朝上的面的点数之和为 s 的事件出现的次数。
for (int s = 1; s <= 6; s++) {
// 初始化 dp 数组
dp[s] = 1;
}
for (int i = 2; i <= n; i++) {
for (int s = 6*n; s >= i; s--) {//点数最小值为i个骰子均为1之和
dp[s] = 0;//因为是从后往前逐个累加,在加到当前点数时,必须把原先存放的n-1个骰子的数据置0,否则累加出错
for (int k = 1; k <= 6; k++) {
if (s - k >= i-1) {//n-1个骰子点数和至少为n-1,当前循环使用i个骰子,所以s-k>=i-1
dp[s] += dp[s - k];
//cout << "dp[" << s << "]=" << dp[s] << endl;
} else {
break;
}
}
}
}
double denominator = pow(6.0, n); // 分母
for (int s = n; s <= 6 * n; s++) {
res.push_back(dp[s] / denominator);
}
return res;
}
};
参考
字节题库 - #剑60 - 中等 - n个骰子的点数 - 1刷
【n个骰子的点数】:详解动态规划及其优化方式
剑指 Offer 60. n 个骰子的点数(动态规划,清晰图解)