把地窖和单向通道看成 DAG,按编号从大到小做线性 DP,dp[u] 表示从 u 出发能挖到的最多地雷,同时记录 nxt[u] 恢复路径。
OJ: roj
题目 ID: 1262
难度:普及-
标签:线性DPDAG图论DP
创建: 2026-09-30 02:13
更新: 2026-09-30 02:16
形式化题目
给定 0 0 结束。边表示可以从
要求从任意一个地窖出发,找一条有向路径,使得路径上所有地窖的地雷数之和最大。输出这条路径(点编号用 - 连接)以及最大地雷总数。
正解
思路
因为所有边都从小编号指向大编号,所以整张图是一个有向无环图(DAG)。点编号
设:
:从地窖 出发,一直走到无路可走,最多能挖到的地雷总数。 :最优路径中 下一步要去的地窖编号。若 后面不再走,则 。
由于
如果
全局最优起点就是
样例 DP 表
以下表展示样例按
| 出边指向 | 已算出的 |
||||
|---|---|---|---|---|---|
| 6 | 5 | 无 | — | 5 | 0 |
| 5 | 4 | 6 | 5 | 9 | 6 |
| 4 | 5 | 5, 6 | 9, 5 | 14 | 5 |
| 3 | 20 | 4 | 14 | 34 | 4 |
| 2 | 10 | 4 | 14 | 24 | 4 |
| 1 | 5 | 2, 4 | 24, 14 | 29 | 2 |
最大
代码
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-07-11 22:00
# update_at: 2026-07-11 22:00
import sys
NEG = -10**18
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n = next(data)
a = [0] + [next(data) for _ in range(n)] # 1-indexed 地雷数
g = [[] for _ in range(n + 1)]
while True:
x, y = next(data), next(data)
if x == 0 and y == 0:
break
g[x].append(y)
dp = [0] * (n + 1) # 从 i 出发能挖到的最多地雷
nxt = [0] * (n + 1) # 最优路径的下一个点,0 表示结束
for u in range(n, 0, -1):
best, nxt_u = NEG, 0
for v in g[u]:
if dp[v] > best:
best, nxt_u = dp[v], v
dp[u] = a[u] + (best if best != NEG else 0)
nxt[u] = nxt_u
start = max(range(1, n + 1), key=lambda i: dp[i]) # 全局最优起点
path: list[str] = []
u = start
while u:
path.append(str(u))
u = nxt[u]
print('-'.join(path))
print(dp[start])
if __name__ == "__main__":
solve()复杂度
- 时间复杂度:
, 为边数。每个点处理一次,每条出边枚举一次。 - 空间复杂度:
,存储邻接表、 、 数组。
总结
本题的本质是在一个边方向严格递增的 DAG 上求点权和最大的路径。利用拓扑序的显式结构,直接用逆序线性 DP 即可:0 0 结束。