感觉本题用top-down的递归要比bottom up的动态规划更好写。
我们将所有任务按照从大到小的顺序排序。令dp[i][j]表示用j个工人完成blocks[i:end]的最少时间。我们有两种决策:
- 当前我们不派工人干活,只派工人分裂,这样需要花费固定split的时间,索性贪心些,将人数double一下。所以
dfs(i,j) = split + dfs(i, j*2)
- 当前我们至少派一个工人干活,干什么活呢?肯定是干耗时最长的活(也就是blocks[i]),因为我们可以把耗时短的工作放在稍后去做,起到尽量并行完成的目的。因此
dfs(i,j) = blocks[i] + dfs(i+1, j-1)
.
当然,我们也可以在当前派两个工人干活,这样的话就是dfs(i,j) = blocks[i] + dfs(i+1, j-2)
.但是注意到,这个决策其实是包含在上面的第二个决策里的,我们不需要重复去列举。否则我们如果枚举当前指派干活的工人人数,会TLE。
边界条件有这么几种:
- 工作干完了,即
i=blocks.size()
. - 工作没干完,但没有工人了,即
j==0
,这时候无法做任何操作了(包括分裂)。 - 工人比工作的数量多,那么就直接让所有工人都并行开工,这样答案就是blocks[i].