1723. 完成所有工作的最短时间

题目描述

给了一个整数数组jobs表示工作,元素ei表示第i个工作需要花费的时间
给k个人,每个工作都需要分配,且每个只能给一个人
问如果要完成所有工作,求最短的工作时间?

f1-状态压缩+动态规划

基本分析

  1. 能看出来需要二进制压缩状态,这里n是工作量,k是人数,怎么定义dp定义好?因为给第i个人的分配工作的时候只和之前i-1个人被分配的工作有关,因此定义dp状态为f[i][j],表示给前i个人分配工作状态为j时候的最小时间
  2. 考虑怎么转移?加入给第i个人分配的工作是mask的一个子集sub,那么前i-1个人做的工作就是mask^sub,本次分配对应的时间就是max(f[i-1][mask^sub],value[i]);因为这个不一定是最合理的,我们需要枚举mask的子集sub,来让总和最小
  3. 考虑以上转移,是不是可以对value做预处理?可以遍历mask的子集sub,把sub对应的时间存起来
  4. 怎么考虑dp的初始状态?考虑只由第一个人做的时候,mask对应的时间就是我们上一步求的sub对应的时间。
  5. 转移的时候怎么考虑?
    • (1)先遍历人i,因为i=0给了初值,且要看i-1的状态,i从1开始就行
    • (2)再遍历状态sub,对应每个sub给一大的初始时间inf,再初始化他的子集last=sub
    • (3)枚举sub的子集last,看不同的prev和last的组合时间是多少,选出最小的就是f[i][sub]的结果
  6. 以上复杂度很高,可以考虑怎么优化?
    • (1)python的min和max比较复杂,需要写成直接比较值的形式
    • (2)在函数之外,把mask的子集存起来,写成subsets[mask]的形式
    • (3)在枚举子集的时候借用二分等,后面再细看

代码

subsets = [[] for _ in range(1<<12)]
for i in range(1<<12):
s = i
while s > 0:
subsets[i].append(s)
s = (s-1) & i
class Solution:
def minimumTimeRequired(self, jobs: List[int], k: int) -> int:
n = len(jobs)
mask = 1<<n
ssum = [0] * mask
for sub in range(mask):
for j in range(n):
if sub & (1<<j):
ssum[sub] = ssum[sub ^ (1<<j)] + jobs[j]
break
f = [[0]*mask for _ in range(k)]
f[0] = ssum.copy()
for i in range(1, k):
for j in range(1, mask):
last = j
mint = inf
for last in subsets[j]:
prev = j - last
curt = ssum[last] if ssum[last] > f[i-1][prev] else f[i-1][prev]
mint = mint if mint <= curt else curt
f[i][j] = mint
return f[-1][-1]

复杂度

时间:O(2n)dpO(n2n)kn cdotCnk2k=3nO(n3n)
空间:O(n2n)

总结

  这个题在写状态的时候需要考虑怎么转移的问题,这里线索第i个人要分配的任务需要看前i-1个人的分配情况,这样就建立起来了联系,把人放在第1维度,把对应的任务状态放在第2维度,f[i][j]表示前i个人完成任务j对应的最小时间。
  这里需要考虑预处理,是因为在转移的时候,需要知道某个任务组合如果都给一个人做的时候,需要总共多少时间,这个可以提前累加起来。同时在累加的时候,由于子集是从小到大的,对于某个大的sub,肯定是可以找到一个低位的j,ssum[sub] = ssum[sub^(1<<j)] + jobs[j]是肯定成立的,之后就能break,去找下一个sub,这样节省时间。
  给dp赋初值的时候,考虑到我们枚举人是需要往前看的,所以i要从1取,那么i=0的情况要初始化好,恰好i等于0时候就代表只派0号人去做,这个结果在ssum中刚好已经统计了。
  常规转移的时候,先枚举人,再枚举状态,再枚举状态的子集。这个题python不好过,需要一些小技巧优化,前两个只是技巧,后面考虑二分优化需要再彻底了解下。

posted @   zhangk1988  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示