P1113 [USACO02FEB] 杂务(黄色 普及/提高-)
dp, topological order, https://www.luogu.com.cn/problem/P1113
John 的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。
当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务
John 有需要完成的
写一个程序依次读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定 John 的农场有足够多的工人来同时完成任意多项任务。
输入格式
第
第
- 工作序号(保证在输入文件中是从
到 有序递增的); - 完成工作所需要的时间
; - 一些必须完成的准备工作,总数不超过
个,由一个数字 结束。有些杂务没有需要准备的工作只描述一个单独的 。
保证整个输入文件中不会出现多余的空格。
输出格式
一个整数,表示完成所有杂务所需的最短时间。
输入输出样例 #1
输入 #1
7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0输出 #1
23这是一个典型的有向无环图(DAG)上的动态规划(DP)或拓扑排序问题。
解题思路
依赖关系与拓扑序: 题目中明确指出:“杂务
的准备工作只可能在杂务 至 中”。这意味着输入给出的任务顺序已经天然满足拓扑序。我们不需要显式地进行拓扑排序,只需要按照任务编号从 到 顺序计算即可。 状态定义: 设
表示完成第 个杂务所需的最短时间(即该任务的最早完工时间)。 状态转移方程: 对于任务
,它必须在它所有的准备工作完成之后才能开始。因此,它的开始时间取决于其所有准备工作中完工时间最晚的那一个。 如果任务
没有准备工作,则对应的最大值为 。 最终答案: 所有任务都完成的最短时间为所有任务完工时间的最大值,即
。
Python 代码实现
import sys
def solve():
# 读取所有输入数据
input_data = sys.stdin.read().split()
if not input_data:
return
n = int(input_data[0])
# dp[i] 表示完成第 i 个杂务的最短时间
dp = [0] * (n + 1)
ptr = 1
for _ in range(n):
u = int(input_data[ptr])
length = int(input_data[ptr+1])
ptr += 2
max_prev_dp = 0
# 读取准备工作,直到遇到 0 结束
while True:
pre = int(input_data[ptr])
if pre == 0:
ptr += 1
break
if dp[pre] > max_prev_dp:
max_prev_dp = dp[pre]
ptr += 1
# 转移方程
dp[u] = length + max_prev_dp
# 最终输出完成所有任务所需的最短时间
print(max(dp))
if __name__ == '__main__':
solve()复杂度分析
- 时间复杂度:每个任务和每个依赖关系都只会被遍历一次。题目规定每个任务的准备工作总数不超过 100 个,因此总时间复杂度为
,在 的情况下运行效率较高。 - 空间复杂度:需要一个大小为
的数组来存储每个任务的 值,空间复杂度为 。