题目描述
你需要制定一份 d 天的工作计划表。工作之间存在依赖,要想执行第 i 项工作,你必须完成全部 j 项工作( 0 <= j < i)。
你每天 至少 需要完成一项任务。工作计划的总难度是这 d 天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大难度。
给你一个整数数组 jobDifficulty 和一个整数 d,分别代表工作难度和需要计划的天数。第 i 项工作的难度是 jobDifficulty[i]。
返回整个工作计划的 最小难度 。如果无法制定工作计划,则返回 -1 。
提示:
1 <= jobDifficulty.length <= 300
0 <= jobDifficulty[i] <= 1000
1 <= d <= 10
思路
题目可以抽象为将n个数字分为d段,每段中最大的数字代表本段,求所有段最大值之和的最小值。
考虑动态规划,动规三个重点,状态如何表示、初始值的设置、状态转移方程。
状态用f[i,j]表示前i天做前j项工作的最小工作量;
初始值为用一天时间完成前j项工作的最小工作量;
状态转移为前i-1天完成j-k项工作,j-k+1、j-k+2、......j 项工作在第i天完成,方程表示为 f[i,j] = min( f[i-1, j-k] + max_value(j-k+1, j) );
可提前计算max_value数组,表示从i到j的最大值,代码如下
1 class Solution { 2 public int minDifficulty(int[] jobDifficulty, int d) { 3 int n = jobDifficulty.length; 4 if (n < d) return -1; 5 int[][] f = new int[d + 1][n + 1]; 6 int[][] max = new int[n + 1][n + 1]; 7 for (int i = 1; i <= n; i++) { 8 int max_value = -1; 9 for (int j = i; j <= n; j++) { 10 if (jobDifficulty[j - 1] > max_value) max_value = jobDifficulty[j - 1]; 11 max[i][j] = max_value; 12 } 13 } 14 for (int i = 1; i <= n; i++) f[1][i] = max[1][i]; 15 for (int i = 2; i <= d; i++) 16 for (int j = 1; j <= n; j++) 17 f[i][j] = Integer.MAX_VALUE; 18 for (int i = 2; i <= d; i++) { 19 for (int j = i; j <= n; j++) { 20 for (int k = 1; j - k >= i - 1; k++) { 21 f[i][j] = Math.min(f[i][j], f[i - 1][j - k] + max[j - k + 1][j]); 22 } 23 } 24 } 25 return f[d][n]; 26 } 27 }