最近在学最短路的各种算法,参考了各位菊苣的心得以及相关资料,觉得很有必要自己总结下!
Dijkstra算法:
适用于 无负权边,无环(视所求得“最短”定义而论)的图的单源最短路问题(也就是考虑一个点)。
常用 dist[i] 数组存储源点 到 i 点的距离,应用贪心的思想,每次 从 未选 点集中 选出距离已选点集最近(最优)的一个点,然后将此点加入已选点集,尝试通过此点 更新 源点 到未选点集 的距离(dist[i]数组),
即dist[i] = min( dist[i],dist[t] + w(t,i) ),其中点 t 是此时新加入已选点集的点,w(t,i) 为 点 t 到 i 的权值。
注意到程序在选择最优的点很耗时,可以借助优先队列(常用STL)进行优化,每次取队头元素操作即可,非常实用!
Bellman-ford 算法:
适用于 带负权边 的 有向图 的单源最短路问题,但图中不能包含权值总和为 负 的回路(此时无最优解),负权无向边不能处理也是这个道理。
可作为 负权 回路 是否存在的判断算法。
标准的算法思想网上一大堆,可以参考北大课件。
算法处理方法一般是边,对于一个具有 n 个顶点的图,从源点到任意顶点最多经过 不构成 负权值回路 的 n - 1条边,
那么更新对dist[i]数组的更新最多也就是n - 1次(称作 松弛),如果还能进行第n 次松弛,是否还会影响dist的值,那
么就可以判断是否存在图中存在 环,有环的情况可能在n -1 次松弛就已经发生了(影响dist的值),但并不影响结论(环可以无限更新dist),所以一般处理n-1次。
当然,如果在某次松弛n条边后,所有dist都没变,那么就可以提前结束!
思想和Dijkstra很类似,但Dijkstra算法中,某点v一旦确定了,dist[v]就不会变了,然而Bellman-ford中不一定。
SPFA算法:
Bellman-ford算法的改进版(更快)。
与Dijkstra算法优先队列实现相似,但可以通过增加updateTimes[i]数组 或者 inqe[i] 数组,来判断 顶点i 更新的次数(更新次数达到n 时存在环) 或者 是否在队列 中,来进一步优化。
建议边做题边思考
POJ 3159,2387 Dijkstra算法优先队列实现
POJ 3259,2240,1860 Bellman-ford,spfa算法模板题
Floyd算法:
尝试将 i -> j 道路 更新成 i -> k -> j ,即在 点 i 到 j 的 边,插入中间点k ,来更新 i -> j 路的长度。
思路清晰,方法简单,但要注意 枚举插入的点 k 要放在 最外层 循环!!!