CSP-J 图论 · Floyd 第 2 梯 · 理解 k 的本质

P1119 灾后重建

同样是问最短路,但点会随时间一个个“修好”。这正好对上 Floyd 最外层 k 的含义。

一、先回答问题

结论

每修好一个村庄,就把它当作一个新的中转点 k,跑一层 Floyd。 因为询问时间不下降,所有询问只需一遍 Floyd 就能边解锁边回答。

先别这么写

每个询问都把可用点重新跑一遍完整 Floyd? 那是 O(询问 × n³),会超时。关键是不要重复劳动。

二、核心观察

关键对应

Floyd 最外层 k 的含义是:“现在允许把第 k 个点当中转站”

而本题里村庄是按修复时间先后一个个变得可用的 —— 这不就是 “按顺序开放中转点”吗?于是把村庄按修复时间排序,修好一个就跑一层对应的 k,天衣无缝。

三、互动演示:时间推进,村庄逐个解锁

样例 4 个村庄(编号 0~3),修复时间分别是 1、2、3、4 天。问 0→1 的最短路。

dist(0 → 1)
此刻询问答案

四、自己选答案

Q1. 为什么本题不能每次询问都重跑完整 Floyd?

Q2. 处理询问前,村庄应该按什么排序?

Q3. 询问 (x, y, t),什么时候必须输出 -1?

五、手推结果(样例 4 个询问)

询问此刻已修好0→1输出
t=2,问 0→20,1村庄2没修好-1
t=2,问 0→10,1∞(不通)-1
t=3,问 0→10,1,20→2→1 = 55
t=4,问 0→10,1,2,30→2→3→1 = 44

六、C++14 参考代码(核心片段)

注意那个不断前进的指针 k
① 村庄按修复时间排序,用指针 now 记录“已经解锁到第几个”。
② 每解锁一个村庄,就以它为 k一层(两重 i,j 循环),而不是整套三重循环。
③ 回答前先判:x、y 都已解锁,且 dist[x][y]≠INF,否则输出 -1。

七、接着练(同梯度)