leetcode1155 Number of Dice Rolls With Target Sum (tag DP)

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

1.思路 & 解法

從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];
}
複製代碼

2. 優化

顯然,對於這裏的遞推公式,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];
}
複製代碼

3. 優化Extra

3.1 空間優化,size = d * f 是否還能夠優化,能夠改爲什麼,爲何?
3.2 時間優化,memcpy也會消耗時間,如何進行優化?

projectui

相關文章
相關標籤/搜索