核心思路
本题是一个典型的有向无环图(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], 0if pre:for ind in pre: maxn = max(maxn, dp[ind])dp[cur] = maxn + time
total_time = max(dp)
print(total_time)
代码解析
dp = [0] * (n + 1): 创建dp数组,dp[i]存储第i个杂务的最早完成时间。for _ in range(n):: 按输入顺序(即拓扑序)处理每个杂务。ind, time, pre = line[0], line[1], line[2:-1]: 解析出当前杂务的序号、所需时间和前置任务列表。maxn = 0: 用于记录所有前置任务中,最晚的完成时间。for prereq_id in pre: maxn = max(maxn, dp[prereq_id]): 遍历所有前置任务,找到它们完成时间的最大值,即当前任务的最早开始时间。dp[ind] = maxn + time: 根据状态转移方程,计算当前任务的最早完成时间并存入dp数组。total_time = max(dp): 循环结束后,dp数组中记录了所有任务的完成时间。取其中的最大值,即为完成所有任务的总时间。
