开车旅行开车旅行开车旅行
最初想法\color{blue}{最初想法}最初想法
跑一次 FloyedFloyedFloyed, 把加油站独自提出来建一棵树, 跑最小瓶颈路, 时间复杂度 O(N3)O(N^3)O(N3) .
实际上 上方的 FloyedFloyedFloyed 可以换成 NNN 次 DijstraDijstraDijstra 的, 时间复杂度 O(N2)O(N^2)O(N2) .
正解部分\color{red}{正解部分}正解部分
与上方差不多的思路, 只不过优化了 建树过程 .
先说做法:先说做法 :先说做法:
跑 DijstraDijstraDijstra 时, 将所有加油站作为起点, 同时推入 优先队列, 跑最短路, 可以以 O(NlogN)O(NlogN)O(NlogN) 的复杂度得到 普通点离得最近的加油站编号 .
然后可以遍历每条边, 若两个端点离得最近的加油站不同, 则在两个加油站之间连一条经过两个端点的路径 .
最后求出最小生成树, 其余同上 .
为什么这样做 ?为什么这样做\ ?为什么这样做 ?
考虑从加油站 xxx 出发可行的路线, 肯定是走最短路径到达另一个加油站 yyy .
若 xxx 到 yyy 路径上存在一条边 (u,v,w)(u, v, w)(u,v,w) 满足距离 uuu 最近的加油站为 xxx 且距离 vvv 最近的加油站为 yyy, 那么我们会将 (x,y,dist(x,y))(x, y, dist(x, y))(x,y,dist(x,y)) 加入生成树 .
否则可以证明 xxx 到 yyy 的路径不可能在最小生成树中出现:
-
找到一条边 (u,v,w)(u, v, w)(u,v,w), 设距离 uuu 最近的加油站为 aaa, 距离 vvv 最近的加油站为 bbb, uuu距离 xxx 近,vvv 距离 yyy 近 .
-
由条件可得 dist(a,u)≤dist(x,u)dist(a, u) \le dist(x, u)dist(a,u)≤dist(x,u), dist(b,v)≤dist(y,v)dist(b, v) \le dist(y, v)dist(b,v)≤dist(y,v).
-
因为
dist(a,b)=dist(a,u)+dist(v,b)+w≤dist(x,b)=dist(x,u)+dist(v,b)+wdist(a, b) = dist(a, u) + dist(v, b) + w \\ \le dist(x, b) =dist(x, u)+dist(v, b)+wdist(a,b)=dist(a,u)+dist(v,b)+w≤dist(x,b)=dist(x,u)+dist(v,b)+w
dist(a,y)=dist(a,u)+dist(v,y)+w≤dits(x,y)=dist(x,u)+dist(v,y)+wdist(a, y) = dist(a, u)+dist(v, y)+w \\ \le dits(x, y) = dist(x, u)+dist(v, y)+wdist(a,y)=dist(a,u)+dist(v,y)+w≤dits(x,y)=dist(x,u)+dist(v,y)+w -
所以从 xxx 到 yyy 不会 比
从 xxx 到 bbb 再 从bbb 到 aaa 最后从 aaa 到 yyy 更优 .
以上证明来自 wjz 的 ppt
实现部分\color{red}{实现部分}实现部分
略 .