把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 s。输入 n,打印出 s 的所有可能的值出现的概率。
此题目解法很多,其中使用动态规划法最好理解,代码也比较简洁
1.现在变量有:骰子个数,点数和。当有c个骰子,点数和为k时,出现次数记为dp(c,k)。那与c-1个骰子阶段之间的关系是怎样的?
2.当我有c-1个骰子时,再增加一个骰子,这个骰子的点数只可能为1、2、3、4、5或6。那k个骰子得到点数和为n的情况有:
(c-1,k-1):第c个骰子投了点数1
(c-1,k-2):第c个骰子投了点数2
(c-1,k-3):第c个骰子投了点数3
....
(c-1,k-6):第c个骰子投了点数6
在c-1个骰子的基础上,再增加一个骰子出现点数和为k的结果只有这6种情况!
所以:dp(c,k)=dp(c-1,k-1)+dp(c-1,k-2)+dp(c-1,k-3)+dp(c-1,k-4)+dp(c-1,k-5)+dp(c-1,k-6)(注意当k<6时的处理越界问题)
3.有1个骰子,dp(1,1)=dp(1,2)=dp(1,3)=dp(1,4)=dp(1,5)=dp(1,6)=1。
因此状态转移方程为
dp[c][k]=sum(dp[c-1][k-m])(1<=m<=6&&m
public class Solution {
public String[] printProbability(int n) {
if (n <= 0)
return null;
//结果可能性总数
int total = (int) Math.pow(6, n);
String[] result = new String[6 * n - n + 1];
//dp[c][k] c个骰子朝上一面点数之和为k的次数
int[][] dp = new int[n + 1][6 * n + 1];
//初始化dp[1][1...6]
for (int x = 1; x <= 6; x++)
dp[1][x] = 1;
//执行计算
for (int i = 2; i <= n; i++)
for (int j = 2; j <= 6 * n; j++) {
int sum = 0;
for (int m = 1; m < j && m <= 6; m++)
sum += dp[i - 1][j - m];
dp[i][j] = sum;
}
//统计结果,用分数表示
for (int k = n; k <= 6 * n; k++) {
result[k - n] = dp[n][k] + "/" + total;
}
return result;
}
public static void main(String[] args) {
String[] result = new Solution().printProbability(3);
System.out.println(result.length);
for (String val : result)
System.out.print(val + ",");
}
}
计算结果
16
1/216,3/216,6/216,10/216,15/216,21/216,25/216,27/216,
27/216,25/216,21/216,15/216,10/216,6/216,3/216,1/216,