Bellman-Ford算法(求最短路径,并检测负权回路)

Bellman – ford(贝尔曼-福特)算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在n-1次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成。

算法时间复杂度O(VE)。因为算法简单,适用范围又广,虽然复杂度稍高,仍不失为一个很实用的算法。(百度百科)

网上关于这个算法的讲解文章比较多,总结可分为三个步骤。

1.初始化所有点。dist[]数组保存每个点的值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
  2.进行n-1次循环,循环下标为从1到n-1(n等于图中点的个数)。

在循环内部,遍历所有的边,进行松弛计算

(关于松弛操作不懂的,可以看下这个博客http://www.wutianqi.com/?p=1912)
  3.遍历途中所有的边,判断是否存在dist[edge[j].v]>dist[edge[j].u]+edge[j].w
   存在则返回false,表示途中存在从源点可达的权为负的回路。

《Bellman-Ford算法(求最短路径,并检测负权回路)》

以上图为例,初始,A到B的距离为5,B到C的距离为2,C到A的距离为9;

0+5=5<20,所以B的值变为5,这个过程的意义是,找到了一条通向B点更短的路线,且该路线是先经过点A,然后通过权重为5的边,到达点B。依此遍历。

图中红色为第一次循环后各点新的值,紫色为第二次循环后各点新的值,由于只有三个点,也就是第二部分循环两次结束,进入第三部分。

此时仍然满足-4+5=1<3,即存在负权回路,flag=false;

注意,此算法的返回值为true或false;

贴代码:

#include <stdio.h>
#include <stack>
using namespace std;
#define MAX 10000//假设权值最大不超过10000
struct Edge
{
    int u;//边的起始顶点
    int v;//边终止顶点
    int w;//权
};
Edge edge[1000];
int dist[100];
int path[100];
int vn;//顶点数
int en;//边数
int source;//源点
bool BellmanFord()
{
    //初始化
    for(int i=0;i<vn;i++)
        dist[i]=(i==source)? 0:MAX;
    //n-1次循环
    for(int i=1;i<=vn-1;i++)
        for(int j=0;j<en;j++)
{
    if(dist[edge[j].v]>dist[edge[j].u]+edge[j].w)
    {
        dist[edge[j].v]=dist[edge[j].u]+edge[j].w;
        path[edge[j].v]=edge[j].u;
    }
}
bool flag=true;
//第n次循环判断负权回路
for(int i=0;i<en;i++)
{
    if(dist[edge[i].v]>dist[edge[i].u]+edge[i].w)
        flag=false;
    break;
}
return flag;
}
void print()//利用栈的特性进行存储,方便输出
{
    for(int i=0;i<vn;i++)
    {
        if(i!=source)
        {
            int p=i;
            stack<int> s;
            printf("顶点%d到顶点%d的最短路径是:",source,p);
            while(source!=p)
            {
                s.push(p);
                p=path[p];
            }
            printf("%d",source);
            while(!s.empty())
            {
                printf("--%d",s.top());
                s.pop();
            }
            printf(" 最短路径长度是:%d\n",dist[i]);
        }
    }
}
int main()
{
    printf("请输入图的顶点数 边数 源点:");
    scanf("%d %d %d",&vn,&en,&source);
    printf("请输入%d条边的信息(起点,终点,权值):",en);
    for(int i=0;i<en;i++)
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    if(BellmanFord())
       print();
        else
printf("Sorry,it have negative circle!\n");
    return 0;
}

《Bellman-Ford算法(求最短路径,并检测负权回路)》

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/JYL1159131237/article/details/78505931
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞