Bellman-Ford是另一种单源最短路径算法,他的功能和 Dijkstra算法一样。但是运行速度比 Dijkstra慢。时间复杂度为O(V*E)
因为 Dijkstra对加权有向图里面的负环路不能正常工作。但是Bellman-Ford可以正常工作。
下面介绍Bellman-Ford的工作流程
procedure BellmanFord(list vertices, list edges, vertex source) // This implementation takes in a graph, represented as lists of vertices and edges, // and fills two arrays (distance and predecessor) with shortest-path information // Step 1: initialize graph初始化有向图和Dijkstra一样。 for each vertex v in vertices: if v is source then distance[v] := 0 else distance[v] := infinity predecessor[v] := null // Step 2: relax edges repeatedly重复进行relax操作, for i from 1 to size(vertices)-1: for each edge (u, v) with weight w in edges: if distance[u] + w < distance[v]: distance[v] := distance[u] + w predecessor[v] := u // Step 3: check for negative-weight cycles检测负环路。 for each edge (u, v) with weight w in edges: if distance[u] + w < distance[v]: error "Graph contains a negative-weight cycle"下面证明该算法的正确性:
正确性可以用归纳法证明。
引理. 经过I次重复:
- 如果距离u不是无穷大,那么他等于一些路径从源点到u的长度;
- 如果存在一条路径从源点到u拥有i条边,那么距离u最多为从s到u的最短路径经过最多i条边;
证明. 对于推理的基本情况, 考虑i=0并且在循环被执行第一次之前。那么对于源点,源点的距离是0,这是对的,对于其他的点u,u点的距离是无穷大,也是对的,因为没有从源点到u经过了0条边。
对于归纳情况,我们首先证明第一部分。考虑档点的距离被更新为距离v:=距离u + uv边的权重。更具归纳假设距离u是从源点到u的一条路径的长度。那么距离u+uv边的权重是是一条从源点到u再到v的路径的长度。
对于第二部分,考虑从源点到u包含最多i条边的最短长度。那么该最短路径的一部分从源点到v点会有最多i-1条边。根据归纳推理,距离v是经过i-1轮循环式这条路径的最大长度。然而uv边的权重+距离v是从s到u的最大长度。在第i轮循环距离u和uv边的权重+距离v比较,然后如果uv边的权重+ 距离v 更小 ,距离u将被设置。所以经过i轮循环距离u最多为从s到u的最短路径包括最多i条边。
如果没有负环路,那么所有的最短路径经过每个点最多一次,所以在第三步不需要更多的证明。
相反情况,对于任何环路经过v0 。。。。。v【k - 1】
v[i]<=v[(i - 1) mod k].distance + v[i]<=v[(i - 1) mod k]v[i].weight.