You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求带启动等待时间、可并行处理4任务的工人最短完工时间(类LeetCode1732)

问题分析与解法思路

首先明确:你提到的LeetCode 1732(找最高海拔)和当前任务分配问题完全无关,应该是笔误——你实际想对比的应该是LeetCode 1723《完成所有工作的最短时间》,这是经典的任务分配求最短完成时间问题,当前问题是它的变种,新增了两个关键约束:

  • 每个工人每次最多处理4个任务,一组任务的完成时间为该组任务的最大耗时
  • 工人首次开工需要额外等待时间,后续组无需等待

核心问题拆解

我们的目标是最小化所有工人完成时间的最大值(工人并行工作,总完成时间由最晚结束的工人决定),同时满足:

  1. 所有任务必须全部分配,每个任务仅属于一名工人
  2. 每名工人的任务被划分为若干组,每组最多4个任务
  3. 工人的总完成时间 = 首次等待时间 + 所有组的最大耗时之和

解法思路:二分查找+回溯剪枝

这是解决这类“最小化最大完成时间”问题的通用高效思路,具体步骤如下:

1. 二分查找确定候选时间范围

  • 左边界left:取两个值的最大值:单个任务的最大耗时(任何组的完成时间都不能小于它)、最小等待时间+单个任务最大耗时(最快可能的首次开工完成时间)
  • 右边界right:最坏情况的总时间,比如取sum(wait) + sum(jobs)(足够宽松,不影响二分效率)

2. 回溯验证候选时间是否可行

对于每个候选时间T,判断能否将所有任务分配给k个工人,使得每个工人的总完成时间不超过T。结合以下优化提升效率:

  • 任务降序排序:优先分配耗时大的任务,快速排除不可能的分配方案,减少回溯分支
  • 工人状态跟踪:每个工人记录三个状态:
    • 已完成的总耗时(已结束的所有组的时间总和,包含首次等待时间)
    • 当前正在处理的组的任务数量
    • 当前正在处理的组的最大任务耗时
  • 剪枝策略:
    • 分配任务后总耗时超过T,直接跳过该分支
    • 当前工人和前一个工人状态完全相同,跳过重复计算
    • 当前工人未开始工作且分配失败,直接终止后续工人尝试(后续工人等待时间更长,更不可能满足)

伪代码实现示例

def min_total_time(jobs, k, wait):
    jobs.sort(reverse=True)
    n = len(jobs)

    def is_feasible(T):
        # 工人状态:(已完成总耗时, 当前组任务数, 当前组最大耗时)
        workers = [(0, 0, 0) for _ in range(k)]
        return backtrack(0)

    def backtrack(job_idx):
        if job_idx == n:
            return True
        current_job = jobs[job_idx]
        for i in range(k):
            total, cnt, curr_max = workers[i]
            # 情况1:工人还未开始任何任务
            if cnt == 0:
                new_total = wait[i] + current_job
                if new_total > T:
                    continue
                workers[i] = (new_total, 1, current_job)
                if backtrack(job_idx + 1):
                    return True
                workers[i] = (0, 0, 0)
                # 第一个工人无法分配,后续工人等待时间更长,直接终止
                if i == 0:
                    break
            else:
                # 情况2:当前组还能加任务(不足4个)
                if cnt < 4:
                    new_curr_max = max(curr_max, current_job)
                    workers[i] = (total, cnt + 1, new_curr_max)
                    if backtrack(job_idx + 1):
                        return True
                    workers[i] = (total, cnt, curr_max)
                    if cnt == 0:
                        break
                # 情况3:当前组已满,新开一组
                else:
                    new_total = total + current_job
                    if new_total > T:
                        continue
                    workers[i] = (new_total, 1, current_job)
                    if backtrack(job_idx + 1):
                        return True
                    workers[i] = (total, cnt, curr_max)
            # 剪枝:避免重复处理相同状态的工人
            if i > 0 and workers[i] == workers[i-1]:
                continue
        return False

    # 确定二分边界
    left = max(max(jobs), min(wait) + max(jobs))
    right = sum(wait) + sum(jobs)
    while left < right:
        mid = (left + right) // 2
        if is_feasible(mid):
            right = mid
        else:
            left = mid + 1
    return left

示例验证

  • 示例1:jobs = [3,3,4,2,9,8,5,6],k=2,wait=[9,11]
    任务降序后为[9,8,6,5,4,3,3,2],二分查找得到最小T=18:
    • 工人1分配[9,8,4,3],总时间9+9=18
    • 工人2分配[6,5,3,2],总时间11+6=17,满足≤18
  • 示例2:1名工人,wait=3,任务[2,1,1,1,1]
    无论如何分组,总时间都是3 + max(1,1,1,1) + max(2) = 3+1+2=6,符合预期

内容的提问来源于stack exchange,提问作者user1691278

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:22:34