最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由节点和路径组成的)中两节点之间的最短路径。
由于竞赛中不考查文中所述算法的证明,故本文不探讨与证明相关的内容,如有需要请自行查阅维基百科。
#性质
- 对于边权为正的图,任意两个节点间的最短路不会重复经过某一个点或某一条边。
- 对于边权为正的图,任意两个节点间的最短路中的任意一条的节点数不会超过 ,边数不会超过 。
#确定起点的最短路径问题
这种问题也叫单源最短路问题,即已知起始节点,求最短路径的问题。在边权非负时适合使用 Dijkstra 算法,若边权为负时则适合使用 Bellman-ford 算法或者 SPFA 算法。
#Dijkstra 算法
该算法的时间复杂度为 ,使用堆优化后可达 。
#演示
Dijkstra 算法每次取出未访问节点中距离最小的节点,并用该节点更新其他节点的距离。(在演示过程中访问过的节点会被标为红色)
#实现
设起点为 ,终点为 。
- 初始化 ,其余节点的 值为 。
- 找出一个未被标记的 最小的节点 ,并将其加入集合 。
- 扫描节点 的所有出边 ,若 则使用 更新 。
- 重复 2、3 两个步骤直到 。
#代码
题目链接:849. Dijkstra 求最短路 I - AcWing
1 |
|
#堆优化的 Dijkstra 算法
使用堆优化的 Dijkstra 算法的时间复杂度为
#实现
使用堆代替找距离最近的点的操作即可。
由于 C++ STL 中的优先队列不支持删除元素的操作,所以队列中会有重复元素导致复杂度变为 ,但比手写堆要容易许多。
#代码
1 |
|
#Bellman-Ford 算法
该算法的时间复杂度为 (对于存在最短路的图)。
#实现
遍历所有边 ,若 则使用 更新 ,到没有更新操作发生时停止。
在没有负环的情况下最多遍历 次所有边即可得到最短路。
#判断负环
在第 次遍历后如果仍能更新最短路径长度则可以判断存在负环。
#代码
1 |
|
#SPFA 算法
SPFA 算法在国际上通称为「队列优化的 Bellman-Ford 算法」,仅在中国大陆地区称为 「SPFA 算法」(Shortest Path Fast Algorithm),在随机图上运行效率为 ( 是一个很小的常数),但在特殊构造的图上时间复杂度会退化为为 。
#实现
- 先初始化一个队列,并将起点入队。
- 取出队头 ,并扫描其所有出边 ,若 则使用 更新 ,并将 入队。
- 重复上述步骤直到队列为空。
#SPFA 判负环
在每次更新 dist[x]
的同时记录当前所走过的边数 cnt[x] = cnt[t] + 1
,若 cnt[n]
大于等于 则可以证明存在图中负环。
由于从 号点开始走不能保证走到所有的负环,因此需要将节点 都入队进行查找。
#卡 SPFA
- 生成一棵以起点为根的树,树高尽量高(比如 为起点时,可以令每个点 的父亲在 到 随机),边权随机,作为最短路径树,同时直接递推求出每个点的带权深度
- 对于剩下的边,端点 随机,边权在 到 随机(如果是有向图则去掉绝对值符号, 可以换成其他较小的正数)
这样生成的图中,次短路的条数非常的多,而 SPFA 一旦错误地进入了次短路的分支,就会使得一整棵子树被赋错误的距离,从而在后期不得不重新更新。而由于边权接近,剪枝的效果会受到很大影响。
#代码
SPFA 求最短路
1 |
|
SPFA 判负环
1 |
|
#确定终点的最短路径问题
与确定起点的问题相反,该问题是已知终结节点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
只需要反向存图然后再跑一遍单源最短路即可。
#确定起点终点的最短路径问题
即已知起点和终点,求两节点之间的最短路径。
可以使用单源最短路算法并进行剪枝:在处理完到终点的最短路径后直接停止计算最短路。
#全局最短路径问题
全局最短路径问题也叫多源最短路问题,可以求出图中所有的最短路径。适合使用 Floyd 算法,时间复杂度为 。
#实现
设 表示经过若干个编号不超过 的节点从 到 的最短路径长度。
容易发现,这个问题可以拆分为两个子问题:经过若干个编号不超过 的节点从 到 ,或者从 经过 再到 。可以得出递推式:
那么接下来考虑优化,在每次循环中只会用到 中的数据,可以使用滚动数组的思想压缩数组,所以递推式可以简化为:
这样即可将空间复杂度优化到 。
#代码
1 |
|
#参考资料
- 最短路 - 图论 - OI Wiki
- 最短路问题 - 维基百科
- 戴克斯特拉算法 (Dijkstra 算法) - 维基百科
- Floyd-Warshall 算法 - 维基百科
- Bellman-ford 算法 - 维基百科
- 如何看待 SPFA 算法已死这种说法? - immortalCO 的回答 - 知乎
- 0x61 最短路,《算法竞赛进阶指南》(ISBN 978-7-83009-313-6,河南电子音像出版社),李煜东,2019 年 9 月。