单源最短路径基础算法总结
N:端点数 M:边数
1.Dijkstra
dist[1] = 0, dist[i] = +∞
for i ← 1 to n
t ← 不在s中的距离最近的点
s ← t
用t更新其他点的距离
时间复杂度分析
dist[1] = 0, dist[i] = +∞
for i ← 1 to n
t ← 不在s中的距离最近的点 O(n^2)
s ← t n次
用t更新其他点的距离 m次
朴素版的时间复杂度是\(O(n^2)\)
dist[1] = 0, dist[i] = +∞
for i ← 1 to n
t ← 不在s中的距离最近的点 O(1)
s ← t n次
用t更新其他点的距离 m * log^n
堆优化版时间复杂度是\(mlog^n\)
Q:为什么处理不了负数
因为Dijkstra每轮都要确定一个端点的最终最短路径,而如果存在负权边,那路径可能是需要拐弯的
比如,有以下边,由A出发,求A -> C的最短路
A -> B: 4
A -> C: 5
B -> C: -1
Dijkstra求出结果必然是 A -> C: 5,而实际结果是 A -> B -> C: 3
Q: 为什么边权都是正数时,不存在此问题
边权都是正数时,所有端点的最短路都是对着走到路径的增多不断增大的,因此不存在绕路走反而更近的情况,因此不存在此问题
2.Bellman-Ford
BF算法执行k轮的含义: 经过不超过K条边到达其他点的最短距离
存储下所有边M
置所有点的距离为无穷,dis[1] = 0
- 每轮循环尝试所有边,看能否对dis数组进行更新
- 如果有N条边,那么理论上更新N - 1次就能得到所有
3.SPFA
在Bellman-Ford基础上改进,Bellman_Ford每轮尝试使用所有边进行更新,而SPFA只使用上一轮更新过的点进行向后更新。
4.求负权回路
方法一 Bellman-Ford
BF算法执行k次的意思是,经过不超过K条边,到达其他点的最短距离,因此理论上说,假设图有N个点,那么执行N - 1轮,dis存储的就是所有的点的最短路,如果此时dis在执行一轮,仍然可以更新,那么就必然存在
方法二 SPFA
在SPFA基础上,设置一个cnt数组,存储每个点被更新的次数,理论上任意一个点被更新次数最多就是N-1,如果更新次数≥N,那必然是存在负权回路