今天介绍一种计算单源最短路径的算法Bellman-Ford算法,对于图G=(V,E)来说,该算法的时间复杂度为O(VE),其中V是顶点数,E是边数。Bellman-Ford算法适用于任何有向图,并能报告图中存在负环路(边的权重之和为负数的环路,这使得图中所有经过该环路的路径的长度都可以通过反复行走该环路而使路径长度变小,即没有最短路径)的情况。以后会介绍运行速度更快,但只适用于没有负权重边的图中的Dijkstra算法。Dijkstra算法可以参考我的下一篇博客 单源最短路径之Dijkstra算法
在介绍Bellman-Ford算法之前,先介绍在计算图的单源最短路径的各种算法中都会用到的松弛操作。
// 松弛操作,检查<s, ..., v>的距离是否比<s, ..., u, v>大,是则更新<s, ..., v>为<s, ..., u, v>
void relax(Vertex *u, Vertex *v, int w)
{
if (u->weight == INF || w == INF) return;
if (v->weight > u->weight + w)
{
v->weight = u->weight + w;
v->p = u;
}
}
Vertex是顶点的数据类型,<u,v>是图G中的一条边。顶点Vertex的属性weight记录了该顶点当前距离源点的最短距离,p记录了顶点在其最短距离中的前一个顶点。松弛操作要做的工作就是检查路径<s,...,v>的距离是否比<s,...,u,v>大,是则更新之,并把s到v的距离修改为s到u的距离加上<u,v>的长度,其中<s,...,v>为源点s到顶点v的原来的路径,<s,...,u>为源点s到顶点u的路径。
Bellman-Ford算法的思想就是反复对图G中的边<