剑指 Offer 60. n个骰子的点数
题目描述
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
输入输出
1 2 3 4 5
| 输入: 1 输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
输入: 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, 6n] 一共(5n+1)种可能 最后按照概率相除 时间复杂度 $O(6^n)$ 爆炸
动态规划
设置dp[i][j]
为投完i
枚骰子之后点数j
出现的次数 得状态转移方程如下:$dp[n][j]=\sum_{i=1}^{6} d p[n-1][j-i]$
边界处理:第一阶段的状态:投掷完 1 枚骰子后,它的可能点数分别为 1, 2, 3, … , 6,并且每个点数出现的次数都是 1
1 2 3
| for (int i = 1; i <= 6; i++) { dp[1][i] = 1; }
|
- 动态规划的空间优化(未知)
java实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| class Solution { public double[] dicesProbability(int n) { int[][] dp = new int[n+1][6*n+1]; for(int i = 1; i <= 6; i++){ dp[1][i] = 1; } for(int i = 2; i <= n; i++){ for(int j = i; j <= 6*i; j++){ for(int k = 1; k<=j&&k<=6; k++){ dp[i][j] += dp[i - 1][j - k]; } } } double[] ans = new double[5*n+1]; for(int i = n; i <= 6*n; i++){ ans[i-n] = ((double)dp[n][i] / Math.pow(6,n)); } return ans;
} }
class Solution { public double[] dicesProbability(int n) { int[] dp = new int[6*n+1]; double all = Math.pow(6, n); for(int i = 1; i <= 6; i++){ dp[i] = 1; } for(int i = 2; i <= n; i++){ for(int j = i*6; j >= i; j--){ dp[j] = 0; for(int k = 1; k <= 6; k++){ if(j-k<i-1) break; dp[j] += dp[j-k]; } } } double[] ans = new double[5*n+1]; for(int i = n; i <= 6*n; i++){ ans[i-n] = dp[i] / all; } return ans; } }
|