You have d dice, and each die has f faces numbered 1, 2, ..., f. Return the number of possible ways (out of fd total ways) modulo 10^9 + 7 to roll the dice so the sum of the face up numbers equals target.git
從tag來看動態規劃DP(dynamic programming)問題,什麼樣的問題能夠用動態規劃解?簡單而言,若是f(n) = A1 * f(n-k1) + A2 * f(n-k2)+....+Am * f(n-km) + C,A一、A二、C均爲常數
則可用動態規劃解;github
對於此題而言,咱們由常識可知,
"d個f面骰子組成target"="d-1個骰子組成target-1"+"d-1個骰子組成target-2"+"..."+"d-1個骰子組成target-f",
即遞推公式:f(d,target) = f(d-1,target-1) + f(d-1,target-2) + .... + f(d-1,target-f);
顯然,f(1,1) = 一、f(1,2) = 一、 .... 、f(1,f) = 1;
所以,咱們能夠設計一個寬f*d高d 的二維數組,將第一行的數據f(1,1)、f(1,2)、...、f(1,f)設置爲1,
則第二行、第三行、....、第n行,都可由公式得出。
而f(d,target)爲咱們所需。
複製代碼
代碼以下:數組
int numRollsToTarget(int d, int f, int target){
if (d <= 0 || f <= 0 || d * f < target || d > target) {
return 0;
}
int dp_array[d][f * d];
memset(dp_array, 0, sizeof(int) * d * f * d);
for (int i = 0; i < f; i++) {
dp_array[0][i] = 1;
}
int mod_number = pow(10, 9) + 7;
for (int i = 1; i < d; i++) {
for (int j = i; j < i * f + f && j < target; j++) {
int sum = 0;
//注意邊界 k >= 0
for (int k = j - 1; k >= 0 && k >= j - f; k--) {
sum += dp_array[i - 1][k];
sum = sum % mod_number;
}
dp_array[i][j] = sum;
}
}
return dp_array[d-1][target-1];
}
複製代碼
顯然,對於這裏的遞推公式,f(d,target)用不到任何d - 2的結果項f(d-2,m),那麼意味着有 有 (d - 2) * d * f的空間浪費了,咱們來優化一下bash
代碼:優化
int numRollsToTarget(int d, int f, int target){
if (d <= 0 || f <= 0 || d * f < target || d > target) {
return 0;
}
int size = d * f;
int stack1[size];
int stack2[size];
memset(stack1, 0, sizeof(int) * size);
memset(stack2, 0, sizeof(int) * size);
for (int i = 0; i < f; i++) {
stack1[i] = 1;
}
int mod_number = pow(10, 9) + 7;
for (int i = 1; i < d; i++) {
//處理一下不可能項f(d,d-1)
stack2[i - 1] = 0;
for (int j = i; j < i * f + f && j < target; j++) {
int sum = 0;
//注意邊界 k >= 0
for (int k = j - 1; k >= 0 && k >= j - f; k--) {
sum += stack1[k];
sum = sum % mod_number;
}
stack2[j] = sum;
}
memcpy(stack1, stack2, sizeof(int) * size);
}
return stack1[target - 1];
}
複製代碼
projectui