前两节我们写了Floyd-Warshall算法http://blog.csdn.net/wtyvhreal/article/details/43315705和
Dijkstra算法http://blog.csdn.net/wtyvhreal/article/details/43447497
Floyd算法可以解决负权边,但是复杂度高。Dijkstra不能解决负权边(边的权值为负值)的图。Bellman-Ford算法非常简单,核心代码只有4行,并且可以完美的解决带有负权边的图:
内循环循环了m次(m为边的个数),意思是把所有的边都松弛一遍。u,v,w三个数组是用来记录边的信息。例如第i条边存储在u[i],v[i],w[i]中,表示从顶点u[i]到顶点v[i]这条边的权值为w[i].
求下图中1号顶点到其余所有顶点的最短路径。
用一个dis数组存储1号顶点到所有顶点的距离
第1轮至第4轮对所有边进行松弛之后:
只需要进行n-1(n为顶点数)轮就可以了。因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1条边。
最短路径肯定是一个不包含回路的简单路径,即最多n-1条边。
整个Bellman-Ford算法一句话概括:
对所有的边进行n-1次“松弛”操作。
输入数据:
运行结果:
Bellman-Ford算法还可以检测一个图是否含有负权回路,如果在进行n-1轮松弛之后,仍然可以继续松弛,那么次图必然存在负权回路。
Bellman-Ford算法的时间复杂度为O(NM),
优化一:
我们还可以进行优化,Bellman-Ford算法经常会在未达到n-1轮松弛前就已经计算出最短路,n-1其实是最大值,因此添加一个一维数组用来备份数组dis,如果在新的一轮松弛中数组dis不变,则可以提前结束。
优化二:
在每次松弛后,会有一些顶点已经求得了最短路,此后这些顶点的最短路估计值就会一直保持不变,不再受后续松弛的影响,但是每次还要判断是否需要松弛,这里浪费了时间,所以
需要:每次仅对最短路径估计值发生变化了的顶点的所有出边执行松弛操作。