题目描述
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率
- 示例:
输入:2
输出:
[0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
题目思路
该题使用动态规划的方法。
乍一看觉得有些复杂,搞不好还要用到概率论中的公式,会不会是个数学问题呢?
但其实用动态规划的方法,直接分析最后的阶段:第n个骰子扔在地上的时候,点数和s_n会是个什么情况?
s_n = s_n-1 + k (1 <= k <= 6), k为第n个骰子可能的点数,不同的k出现的次数是一样的,不妨设为1次
题目要求输出概率数组,不妨先创建数组存储不同点数和出现的次数,最后再除以总次数就好了。
采用动态规划的自底向上的方法,创建二维数组 int[][]count = new int[n+1][6*n+1];//数组的行代表地上骰子的个数,列代表点数和,数组存储这一种情况会出现的次数。
推导公式为 count[i][j] =
∑
m
=
1
6
\sum_{m=1}^6
∑m=16 count[i-1][j-m]
class Solution {
public double[] dicesProbability(int n) {
int [][] count = new int[n+1][6*n+1];
for(int k=1;k<7;k++) count[1][k]=1;
for(int i=2;i<n+1;i++){
for(int j=i;j<6*i+1;j++){
for(int m=1;m<=6;m++){
if(j>=m)
count[i][j] += count[i-1][j-m];
}
}
}
int sum = 0;
for(int k=n;k<6*n+1;k++) sum += count[n][k];
double [] ans = new double [5*n+1];
for(int i=0;i<5*n+1;i++){
ans[i] = (double)count[n][i+n]/sum;
}
return ans;
}
}