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

来源:互联网 发布:中国网民规模季度数据 编辑:程序博客网 时间:2024/06/06 01:10

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,表示途中存在从源点可达的权为负的回路。


以上图为例,初始,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//假设权值最大不超过10000struct 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();        elseprintf("Sorry,it have negative circle!\n");    return 0;}


阅读全文
0 0
原创粉丝点击