Bellman-Ford algorithm

Bellman-Ford算法描述:

1. Bellman-Ford算法能在一般的情况下解决单源最短路径问题(即允许存在负权边,而Dijkstra算法不允许存在负权边)。

2. Bellman-Ford算法的结果是一个bool值,表明图中是否存在着从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到图G任意顶点v的最短路径dist[v];若存在这样的回路,说明该问题无解,即存在一个从源点s到某一个点的最短路径趋向于负无穷(无限循环可得)。


Bellman-Ford算法过程(伪代码):

<span style="font-size:18px;">Bellman-Ford(G,w,s) :boolean                   //图G ,边集 函数 w ,s为源点  
       for each vertex v ∈ V(G) do           //1阶段 初始化
           dist[v] ←+∞  
       dist[s] ←0;                             //1阶段 初始化结束  
       for i=1 to |v|-1 do                      //2阶段 开始,外循环进行
          for each edge(u,v) ∈E(G) do        //对每条边进行松弛  
             If dist[v]> dist[u]+ w(u,v) then   //松弛判断  
                dist[v]=dist[u]+w(u,v)          //2阶段结束 松弛操作 
       for each edge(u,v) ∈E(G) do           //判断是否存在从源点s可达的负权值回路
           If dist[v]> dist[u]+ w(u,v) then  
             Exit false                         //若存在,问题无解,返回False  
       Exit true                                //若不存在,返回True,存在从源点s到各个点的最短路径</span>

Bellman-Ford算法思想:

1. 首先可以确定的是,图G的任意一条最短路径既不能包含负权值回路,也不能包含正权值回路,因此它最多包含(|v|-1)条边。

2. 从源点s可达的所有顶点如果存在最短路径,则这些最短路径构成一个以s为根的最短路径树。Bellman-Ford算法的迭代松弛操作,实际上就是按顶点距离s的层次,逐层生成这颗最短路径树的过程:

在对每条边进行第一遍松弛的时候,生成了从s出发,层次至多为1的那些树枝,也就是说找到了与s至多有1条边相连的那些顶点的最短路径;

在对每条边进行第二遍松弛的时候,生成了从s出发,层次至多为2的那些树枝,也就是说找到了与s至多有2条边相连的那些顶点的最短路径;

... ...以此类推;

因为最短路径最多包含(|v|-1)条边,所以只需循环(|v|-1)次。

3. Bellman-Ford算法构造一个最短长度数组序列dist1[u],dist2[u],dist3[u],... ,distn-1[u]。其中:

dist1[u]为从源点s到终点u的只经过1条边的最短路径长度,并有dist1[u]=edge[s][u];

dist2[u]为从源点s到终点u的最多经过2条边的最短路径长度;

dist3[u]为从源点s到终点u的最多经过不构成负权值回路的3条边的最短路径长度;

... ...

distn-1[u]为从源点s到终点u的最多经过不构成负权值回路的n-1条边的最短路径长度;

算法的最终目的是计算出distn-1[u],为源点s到u的最短路径长度。

4. 在Bellman-Ford算法中判断是否存在从源点s可达的负权值回路的方法:

思路:在求出distn-1[u]之后,再对每条边<u,v>判断一下:加入这条边后,是否会使得s到顶点v的最短路径再缩短,即判断:dist[u]+w[u,v]<dist[v] 是否成立,如果成立,则说明存在从源点s可达的负权值回路。

例如:


更新迭代n-1后,dist[2]=1,dist[4]=-2;

枚举到w(4,2)时:dist[4]+w(4,2)<dist[2],即出现负权值回路。


Bellman-Ford算法优化:

如果在某一遍的迭代中,并没有进行松弛操作,说明该遍迭代所有边都没有松弛,可以证明, 至此以后,所有的边都不需要再松弛,因此可以提前结束迭代过程。所以优化方法就是设置一个bool变量。

Bellman-Ford(G,w,s) :boolean                   //图G ,边集 函数 w ,s为源点  
       for each vertex v ∈ V(G) do           //1阶段 初始化
           dist[v] ←+∞  
       dist[s] ←0;                             //1阶段 初始化结束  
       for i=1 to |v|-1 do                      //2阶段 开始,外循环进行
          bool flag=false;
          for each edge(u,v) ∈E(G) do        //对每条边进行松弛  
             If dist[v]> dist[u]+ w(u,v) then   //松弛判断  
                dist[v]=dist[u]+w(u,v)          //2阶段结束 松弛操作 
                flag=true;
           if(!flag)
	      break;
       for each edge(u,v) ∈E(G) do           //判断是否存在从源点s可达的负权值回路
           If dist[v]> dist[u]+ w(u,v) then  
             Exit false                         //若存在,问题无解,返回False  
       Exit true                                //若不存在,返回True,存在从源点s到各个点的最短路径

ps:优化后的算法在处理有负权回路的测试数据时,由于每次都会有边被松弛,所以flag每次都会被置为true,因而不可能提前终止外层循环。


  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值