Minimum Difficulty of a Job Schedule 工作计划的最低难度
问题描述:
问题
你需要制定一份 d 天的工作计划表。工作之间存在依赖,要想执行第 i 项工作,你必须完成全部 j 项工作( 0 <= j < i)。
你每天 至少 需要完成一项任务。工作计划的总难度是这 d 天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大难度。
给你一个整数数组 jobDifficulty 和一个整数 d,分别代表工作难度和需要计划的天数。第 i 项工作的难度是 jobDifficulty[i]。
返回整个工作计划的 最小难度 。如果无法制定工作计划,则返回 -1 。
jobDifficulty范围[1,300]
jobDifficulty[i]范围[0,1000]
d范围[1,10]
分析
问题中定义了【最小难度】
最小难度是每天处理任务的最大难度的累加和。
而且每天至少需要完成一个任务,总共有
d
d
d天,所以任务的数量必须是
c
n
t
>
=
d
cnt>=d
cnt>=d,否则就无法符合题目要求,返回-1.
如果每天的工作难度用
h
h
h表示,最小难度
min
(
h
)
=
h
1
+
h
2
+
.
.
.
+
h
d
\min(h) = h1+h2+...+hd
min(h)=h1+h2+...+hd.要使得
min
(
h
)
\min(h)
min(h)最小,就需要累加和最小。
每个
h
h
h都是当天完成任务的最大值,所以前面的
h
h
h发生了变化,可能会影响到后面的
h
h
h。
如果存在最小的难度,那么就一定存在 d 组 d组 d组连续的划分,类似 { h 1 } { h 2 } { h d } \{h1\}\{h2\}\{hd\} {h1}{h2}{hd}.
记
j
o
b
的总数为
N
记job的总数为N
记job的总数为N。
比较暴力的思路就是对每一天的任务,进行枚举,即对于第
i
i
i天,如果第
i
−
1
i-1
i−1天的最后一个任务
j
o
b
[
x
−
1
]
job[x-1]
job[x−1],那么 第
i
i
i天的任务就从
j
o
b
[
x
]
job[x]
job[x]开始,向后扩展到
j
o
b
[
y
]
job[y]
job[y],然后取
m
a
x
j
o
b
[
x
]
→
j
o
b
[
y
]
max{job[x]\rightarrow job[y]}
maxjob[x]→job[y],同时要保证
i
+
1
→
d
i+1\rightarrow d
i+1→d的天数每天至少有1个任务,
d
−
(
i
+
1
)
+
1
<
=
N
−
y
,
d
−
i
−
N
>
=
y
d-(i+1)+1<= N-y, d-i-N>=y
d−(i+1)+1<=N−y,d−i−N>=y.
然后逐一累加,需要枚举大量的组合。
设计dfs, d f s ( i n t d a y , i n t j o b N ) dfs(int day,int jobN) dfs(intday,intjobN)表示在工作时间为day,完成到第 j o b N jobN jobN个任务时,可以得到的最小难度。
时间复杂度
O
(
N
2
)
O(N^2)
O(N2)
空间复杂度:
O
(
N
2
)
O(N^2)
O(N2)
代码
public int N;
public int[] job,rec;
public int minDifficulty(int[] jobDifficulty, int d) {
N = jobDifficulty.length;
if(N<d) return -1;
job = jobDifficulty;
rec = new int[N];
for(int i = 0,max = -1;i<N;i++){
rec[i] = Math.max(max,job[i]);
max = Math.max(max,job[i]);
}
return dfs(d,N-1);
}
public int dfs(int day,int ind){
if(day==1){
return rec[ind];
}
int res = Integer.MAX_VALUE,mx = job[ind];
for(int len= 1;;len++){
int j = ind -len ;
if(j+1<day-1) break;
mx = Math.max(mx,job[j+1]);
int tmp = dfs(day-1,j)+mx;
res = Math.min(res,tmp);
}
return res;
}
纯暴力递归是TLE的
public int N;
public int[] job,rec;
public int[][] memo;
public int minDifficulty(int[] jobDifficulty, int d) {
N = jobDifficulty.length;
if(N<d) return -1;
job = jobDifficulty;
rec = new int[N];
memo = new int[d+1][N+1];
for(int i = 0;i<=d;i++){
Arrays.fill(memo[i],-1);
}
for(int i = 0,max = -1;i<N;i++){
rec[i] = Math.max(max,job[i]);
max = Math.max(max,job[i]);
}
return dfs(d,N-1);
}
public int dfs(int day,int ind){
if(memo[day][ind]!=-1) return memo[day][ind];
if(day==1){
return rec[ind];
}
int res = Integer.MAX_VALUE,mx = job[ind];
for(int len= 1;;len++){
int j = ind -len ;
if(j+1<day-1) break;
mx = Math.max(mx,job[j+1]);
int tmp = dfs(day-1,j)+mx;
res = Math.min(res,tmp);
}
return memo[day][ind] = res;
}
加记忆化
还可以继续优化, To Be Continue…
Tag
Array
Dynamic Programming