把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
题解:
class Solution {
public double[] twoSum(int n) {
//动态规划问题,关键是找出状态转移方程
//确定问题解的表达式。可将f(n, s) 表示n个骰子点数的和为s的排列情况总数
//确定状态转移方程。n个骰子点数和为s的种类数只与n-1个骰子的和有关。因为一个骰子有六个点数,那么第n个骰子
//可能出现1到6的点数。所以第n个骰子点数为1的话,f(n,s)=f(n-1,s-1),当第n个骰子点数为2的话,
//f(n,s)=f(n-1,s-2),…,依次类推。在n-1个骰子的基础上,再增加一个骰子出现点数和为s的结果只有这6种情况!
//那么有:f(n,s)=f(n-1,s-1)+f(n-1,s-2)+f(n-1,s-3)+f(n-1,s-4)+f(n-1,s-5)+f(n-1,s-6)
//上面就是状态转移方程,已知初始阶段的解为:当n=1时, f(1,1)=f(1,2)=f(1,3)=f(1,4)=f(1,5)=f(1,6)=1。
double[] res = new double[n * 5 + 1];
double all = Math.pow(6, n); //所有可能情况
int[][] dp = new int[n + 1][6 * n + 1];
for(int i = 1; i <= 6; i++) {
dp[1][i] = 1;
}
for(int i = 1; i <= n; i++) { //n个骰子
for(int j = i; j <= 6 * n; j++) { //i个骰子的最小和为i
for(int k = 1; k <= 6; k++) {
dp[i][j] += j >= k ? dp[i - 1][j - k] : 0;
if(i == n) {
res[j - i] = dp[i][j] / all; //
}
}
}
}
return res;
}
}