【區間 dp】A005_LC_工作計劃的最低難度(暴搜 / dp)

一、Problem

You want to schedule a list of jobs in d days. Jobs are dependent (i.e To work on the i-th job, you have to finish all the jobs j where 0 <= j < i).

You have to finish at least one task every day. The difficulty of a job schedule is the sum of difficulties of each day of the d days. The difficulty of a day is the maximum difficulty of a job done in that day.

Given an array of integers jobDifficulty and an integer d. The difficulty of the i-th job is jobDifficulty[i].

Return the minimum difficulty of a job schedule. If you cannot find a schedule for the jobs return -1.

Input: jobDifficulty = [6,5,4,3,2,1], d = 2
Output: 7
Explanation: First day you can finish the first 5 jobs, total difficulty = 6.
Second day you can finish the last job, total difficulty = 1.
The difficulty of the schedule = 6 + 1 = 7 

二、Solution

題意:把含有依賴關係的工作分成 d 天來做,求不同工作分配方法得到的最小工作難度。

方法一:暴搜(超時)

  • ii 天我們都可以把工作分成剩下的天數 d 來做,這相當於在數組上畫 dd 條分割線,求每段區間的最大工作難度的最小的總和分割方法。
  • 對於每一天,我們都可以嘗試做 [1,nd][1, n-d] 個工作,所以暴搜一下分割線即可。

這題和 分割回文串 III 其實很像,但還是超時了…

class Solution {
    int dfc[];
    int dfs(int i, int d) {
        if (d == 1) {
            int max = -1;
            for (int j = i; j < dfc.length; j++)
                max = Math.max(max, dfc[j]);
            return max;
        }
        int min = 0x3f3f3f3f, max = 0;
        for (int j = i; j <= dfc.length - d; j++) {
            max = Math.max(max, dfc[j]);
            min = Math.min(min, max + dfs(j+1, d-1));
        }
        return min;
    }
    public int minDifficulty(int[] jobDifficulty , int d) {
        if (jobDifficulty.length < d) return -1;
        dfc = jobDifficulty;
        int res = dfs(0, d);
        return res;
    }
}

複雜度分析

  • 時間複雜度:O(2nd)O(2^{n-d})
  • 空間複雜度:O(n)O(n)

方法二:dp

  • 定義狀態
    • dp[i][j]dp[i][j] 表示前 ii 天完成 jj 項任務的最小難度
  • 思考狀態轉移方程
    • 對於第 ii 天,我們可以在前 i1i-1 天完成 kk>=i1k(k >= i-1) 項任務(每天至少完成一項),然後在第 ii 天完成 k,k+1, ... ,ik,k+1,\ ...\ , i 項任務,那麼第 ii 天的 dpdp 方程應該這樣寫:
    • dp[i][j]=dp[i1][k]+max(dfc[k],...,dfc[i])dp[i][j] = dp[i-1][k] + max(dfc[k], ... , dfc[i])
    • 但爲了取最小工作難度,所以整體的 dp 方程應該這樣寫:
    • dp[i][j]=min(dp[i1][k]+max(dfc[k],...dfc[i]))dp[i][j] = min(dp[i-1][k] + max(dfc[k], ... dfc[i]))i1kj(i-1 \leqslant k \leqslant j) ,因爲前 i1i-1 天至少有 i1i-1 項任務,但不能超過當前可分配任務數 jj
    • 綜上所述,不難得出這是一個求區間最值的問題
  • 思考初始化:
    • dp[0][0]=0dp[0][0] = 0
  • 思考輸出dp[d][n]dp[d][n] 表示用 dd 天完成 jj 項工作的最小難度
class Solution {
    public int minDifficulty(int[] dfc, int d) {
        if (dfc.length < d)
            return -1;
        int n = dfc.length, INF = 0x3f3f3f3f, maxd[][] = new int[n][n];
        for (int i = 0; i < n; i++) {
            maxd[i][i] = dfc[i];
            for (int j = i+1; j < n; j++)
                maxd[i][j] = Math.max(maxd[i][j-1], dfc[j]);
        }
        int[][] dp = new int[d+1][n+1];
        for (int i = 0; i <= d; i++)
        for (int j = 0; j <= n; j++)
            dp[i][j] = INF;
        dp[0][0] = 0;
        for (int i = 1; i <= d; i++)
        for (int j = i; j <= n; j++)
        for (int k = i-1; k < j; k++) {
			dp[i][j] = Math.min(dp[i][j], dp[i-1][k] + maxd[k][j-1]);
		}
		return dp[d][n];
    }
}

複雜度分析

  • 時間複雜度:O(d×n2)O(d × n^2)
  • 空間複雜度:O(n2)O(n^2)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章