Luogu P1113 杂务

核心思路

本题是一个典型的有向无环图(DAG)上的动态规划问题。每项杂务是一个节点,杂务之间的准备关系是图中的有向边。题目要求所有杂务完成的最短时间,即求解这个图中关键路径的长度。

由于题目保证了杂务 \(k\) 的准备工作只可能在 \(1\)\(k-1\) 中,这说明输入已经按拓扑序给出,大大简化了问题。我们无需再进行拓扑排序,可以直接按输入顺序进行动态规划。

状态定义

我们定义 dp[i] 为:完成第 i 项杂务时,所能达到的最早完成时间

状态转移

对于第 i 项杂务,它要开始,必须等到其所有的前置杂务都完成。因此,它的最早开始时间取决于它所有前置杂务中最晚完成的那一个

设杂务 i 的时长为 time_i,其前置杂务集合为 {p_1, p_2, ...}

  • 杂务 i 的最早开始时间 = max(dp[p_1], dp[p_2], ...)
  • 杂务 i 的最早完成时间 dp[i] = (最早开始时间) + time_i

所以,状态转移方程为:dp[i] = max(dp[p] for p in i的前置杂务) + time_i

如果杂务 i 没有前置杂务,则 max 部分为 0。

最终答案

所有杂务都完成的最短时间,就是所有单个杂务完成时间中的最大值。因为只有当最后一个杂务完成时,才算全部完成。最终答案 = max(dp[1], dp[2], ..., dp[n])

参考代码

import sys
input = sys.stdin.readline
n = int(input())
dp = [0] * (n + 1)
for _ in range(n):
    line = list(map(int, sys.stdin.readline().split()))
    cur, time, pre, maxn = line[0], line[1], line[2:-1], 0
    if pre:
        for ind in pre: maxn = max(maxn, dp[ind])
    dp[cur] = maxn + time
total_time = max(dp)
print(total_time)

代码解析

  1. dp = [0] * (n + 1): 创建 dp 数组,dp[i] 存储第 i 个杂务的最早完成时间。
  2. for _ in range(n):: 按输入顺序(即拓扑序)处理每个杂务。
  3. ind, time, pre = line[0], line[1], line[2:-1]: 解析出当前杂务的序号、所需时间和前置任务列表。
  4. maxn = 0: 用于记录所有前置任务中,最晚的完成时间。
  5. for prereq_id in pre: maxn = max(maxn, dp[prereq_id]): 遍历所有前置任务,找到它们完成时间的最大值,即当前任务的最早开始时间。
  6. dp[ind] = maxn + time: 根据状态转移方程,计算当前任务的最早完成时间并存入 dp 数组。
  7. total_time = max(dp): 循环结束后,dp 数组中记录了所有任务的完成时间。取其中的最大值,即为完成所有任务的总时间。
posted @ 2025-08-05 15:47  AFewMoon  阅读(12)  评论(0)    收藏  举报