最短路算法

本文时间复杂度中: $n$ 为节点数, $m$ 为边数。
朴素版Dijkstra $O(n^2)$
思路:
从源点开始,先更新与源点间的距离;再找到一个与源点距离最近的点,用这个点作为中继,比较剩余点经该点中继再到源点的距离是否比原来近,近则更新,否则不变,再在剩余的点中查找与源点最近的点,开始下一次循环。
上代码!
1 |
|
堆优化版Dijkstra $O(mlogn)$
朴素版 Dijkstra 算法的性能瓶颈在于每次都要在 st 数组中标记为 false 的点中查找dist最小的点;因此可以考虑使用堆来优化。
1 |
|
由于 Dijkstra 算法只能处理边权为非负数的情况,因此有了下面可以处理负权边的算法。
虽然有负权边,但是不可以有负权回路。
Bellman-Ford算法 $O(m \times n)$ (有边数限制的最短路算法)
给定一个 $n$ 个点 $m$ 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出从 $1$ 号点到 $n$ 号点的最多经过 $k$ 条边的最短距离,如果无法从 $1$ 号点走到 $n$ 号点,输出impossible。
注意:图中可能 存在负权回路。
思路:
$Bellman-Ford$ 算法外层循环循环指定次数 $k$ 次,每次循环都便利所有的边,再利用三角不等式 $dist[epos] \ge dist[spos] + weight$比较并更新 dist。
该算法需要注意防止串联,因此每次循环都要先备份 dist。
1 |
|
SPFA算法 一般 $O(m)$,最坏 $O(m \times n)$ (可用于判断是否存在负环)
该算法属于 $Bellman-Ford$ 算法的优化,使用 $BFS$,队列中只放入被更新过后 dist 变小的点编号。
1 |
|
若用于判断负环存在性
因为负环存在时,一定不存在最短路,程序会死循环。因此记录一下各个点被访问到的序号,一出现某点被访问到的序号大于总点数,表明存在负环,返回退出。
1 | //部分代码 |
Floyd算法 $O(n^3)$ 多源汇最短路
基于动态规划。状态转移方程:
代码非常简单,但是只能处理非负权边。
1 |
|