类似青蛙跳台阶的问题
第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) 这个等式只是在 第n个点数为1的时候,所有考虑的全部的情况,那就是 6种情况全部考虑进去
static int getNumCount(int n, int sum) {
// n为骰子数,sum,n个骰子数的大小
// 3种越界的情况
if (n < 1 || n > sum || sum > 6 * n) {
return -1;
}
// 1个骰子的话,所有的情况只有1种可能
if (n == 1) {
return 1;
}
// 类似青蛙跳台阶的问题
// 第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) 这个等式只是在 第n个点数为1的时候,所有考虑的全部的情况,那就是 6种情况全部考虑进去
return getNumCount(n - 1, sum - 1) + getNumCount(n - 1, sum - 2) + getNumCount(n - 1, sum - 3)
+ getNumCount(n - 1, sum - 4) + getNumCount(n - 1, sum - 5) + getNumCount(n - 1, sum - 6);
}
public static void main(String[] args) {
// 假定值
int n = 5;
int[] count = new int[6 * n + 1];
for (int i = n; i <= 6 * n; i++) {
count[n] = getNumCount(n,i);
}
}
递归的方法就会发生 某一个n和sum的组合被多次的计算,所以我们需要对他进行剪枝。
剪枝的方法一般是通过空间来换取时间,所以我们使用额外空间来保存计算过的结果。
使用二维数组,空间复杂度还是有点高。
static int[][] getNumCount1(int n) {
int[][] count = new int[n + 1][6 * n + 1];
count[1][1] = count[1][2] = count[1][3] = count[1][4] = count[1][5] = count[1][6] = 1;
for (int i = 2; i <= n; i++) {
for (int j = i; j <= 6 * i; j++) {
int temp1 = j - 1 < 1 ? 0 : count[i - 1][j - 1];
int temp2 = j - 2 < 1 ? 0 : count[i - 1][j - 2];
int temp3 = j - 3 < 1 ? 0 : count[i - 1][j - 3];
int temp4 = j - 4 < 1 ? 0 : count[i - 1][j - 4];
int temp5 = j - 5 < 1 ? 0 : count[i - 1][j - 5];
int temp6 = j - 6 < 1 ? 0 : count[i - 1][j - 6];
count[i][j] = temp1 + temp2 + temp3 + temp4 + temp5 + temp6;
}
}
return count;
}
一维数组
/****************************************
func:给定骰子数目n,求所有可能点数和的种类数
para:n:骰子个数;count:存放各种点数和的种类数,下标i表示点数和为(i+n)
****************************************/
static int[] getNumCount2(int n) {
if (n < 1)
return null;
int[] count = new int[5*n+1];
//初始化最初状态
count[0] = count[1] = count[2] = count[3] = count[4] = count[5] = 1;
if (n == 1) return null;
for (int i = 2; i <= n; ++i) {
for (int sum = 6 * i; sum >= i; --sum) {
int tmp1 = ((sum - 1 - (i - 1)) >= 0 ? count[sum - 1 - (i - 1)] : 0); //上一阶段点数和sum-1的排列总数
int tmp2 = (sum - 2 - (i - 1) >= 0 ? count[sum - 2 - (i - 1)] : 0);
int tmp3 = (sum - 3 - (i - 1) >= 0 ? count[sum - 3 - (i - 1)] : 0);
int tmp4 = (sum - 4 - (i - 1) >= 0 ? count[sum - 4 - (i - 1)] : 0);
int tmp5 = (sum - 5 - (i - 1) >= 0 ? count[sum - 5 - (i - 1)] : 0);
int tmp6 = (sum - 6 - (i - 1) >= 0 ? count[sum - 6 - (i - 1)] : 0);
count[sum - i] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6;
}
}
return count;
}