题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
思路:因为暴力递归效率很低,这里我就没去看了。看一下优化的方法使用for循环
有些类似动态规划,因为f(n) = f(k-1)+f(k-2)...f(k-6),意思也就是我们当前所求的n个骰子和为k的次数=和为k-1出现次数+和为k-2出现次数+...和为k-6出现次数的总和。本质就是多投入一个骰子因为6个面6个点数的存在累加了1-6出现不同的情况总和。基于这种思想看代码就基本理解了。
其中的E二维数组是用来循环存储上一次值得,所以复用的时候不能忘了重置
public void printProbability(int number) {
if (number <= 0) return;
int maxValue = 6;
int flag = 0;
int[][] probabilites = new int[2][maxValue * number + 1];
// 首先初始化第一个骰子,每个点数出现的次数为1
for (int i = 1; i <= maxValue; i++) {
probabilites[flag][i] = 1;
}
// 从第二个骰子至第n个骰子做计算
// 骰子为k时,sum取值范围为k~k*maxValue
for (int k = 2; k <= number; k++) {
flag = 1 - flag;
// 在开始统计前先清除要用的数字(<k的)
for (int i = 1; i < k; i++) {
probabilites[flag][i] = 0;
}
// k个骰子点数范围在k~k*maxValue,k处的先置0在进行计算
for (int i = k; i <= maxValue * k; i++) {
// 在计数前先清零该位置
probabilites[flag][i] = 0;
int count = 1;
while (i - count > 0 && count <= 6) {
probabilites[flag][i] += probabilites[1 - flag][i - count];
count++;
}
}
}
// 开始打印
DecimalFormat decimalFormat = new DecimalFormat("0.000");
double pow = Math.pow(maxValue, number);
for (int i = number; i <= maxValue * number; i++) {
String probability = decimalFormat.format(probabilites[flag][i] / pow);
System.out.println(probability + "");
}
}
时间复杂度:O(mn)
空间复杂度:O(mn)