猫走最短路;点 u 安全,当且仅当老鼠能选一条 u→鼠洞 的路径,路径上每个点 x 老鼠的到达时间都 严格小于 猫的最短到达时间 D[x]。求所有安全点的奶酪和。
D[x](猫到各点最短时间);②从鼠洞做一次 “取最大”的反向 Dijkstra,求每点的最晚出发限额 G[x]。G[i]>0 的点就是安全点。课堂安排:先讲清“安全=路径上处处早于猫”,再推为什么限额能反向传播,最后手算样例 1 得 22。
定义 G[x] = “在点 x 最晚什么时刻出发,还来得及安全逃到鼠洞”。在鼠洞 b,安全的硬上限就是猫到达它的时间:G[b]=D[b]。
若从 v 走一条边 (v,u,w) 到 u,则在 v 的限额受两条约束:到 v 本身要早于猫 D[v];走到 u 后还要满足 u 的限额,即出发时刻 +w < G[u]。合并:
G[v] = max( G[v], min( D[v], G[u] - w ) ) —— 取“能用的最大限额”,所以用大根堆反向跑 Dijkstra。最后 G[i]>0 表示“时刻 0 待在 i 仍安全”,即 i 是安全点。
图:5 点,猫窝 a=1,鼠洞 b=2,边权见连线。奶酪 c=[1,2,4,8,16]。
边:1-2(4) · 2-3(3) · 3-4(1) · 2-5(2) · 3-1(8)
Q1. 求 D[x](猫到各点最短时间)该用哪种算法?
Q2. 反向传播限额时,优先队列应当每次取出?
Q3. 为什么 D、G 和奶酪和都要用 long long?
| 点 x | 1 | 2(鼠洞) | 3 | 4 | 5 |
|---|---|---|---|---|---|
| D[x] 猫最短 | 0 | 4 | 7 | 8 | 6 |
| G[x] 限额 | 0 | 4 | 1 | 0 | 2 |
| 安全? (G>0) | 否 | ✅ | ✅ | 否 | ✅ |
| 奶酪 | 1 | 2 | 4 | 8 | 16 |
priority_queue<Node> 默认大根堆取最大限额;③统计时只累加 G[i]>0 的点(严格大于,等于不算)。long long(距离/总和溢出);把“严格大于”写成“大于等于”;初始化 G 要用 -INF 而不是 0。复杂度:两次类 Dijkstra,O(m log n);空间 O(n+m)。迁移:P1396 营救(路径最大边)、P1073 最优贸易(图上 DP 式更新)。