单源最短路径——Bellman--Ford算法

Bellman–Ford算法可以处理路径权值为负数的单源最短路径问题。

时间复杂度  o(n*m)

    设想可以从图中找到一个环路,且这个环路中所有路径的权值之和为负。那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。而Bellman–Ford算法具有分辨这种负环路的能力。

基本算法:

    Bellman–Ford算法基于动态规划,反复用已有的边来更新最短距离,Bellman–Ford算法的核心思想是松弛。如果dist[u]和dist[v]满足dist[v]<=dist[u]+map[u][v],dist[v]就应该被更新为dist[u]+map[u][v]。反复地利用上式对dist数组进行松弛,如果没有负权回路的话,应当会在n-1次松弛之后结束。原因在于考虑对每条边进行1次松弛的时候,得到的实际上是至多经过0个点的最短路径,对每条边进行两次松弛的时候得到的是至多经过1个点的最短路径,如果么有负权回路,那么任意两点间的最短路径至多经过n-2个点,因此经过n-1次松弛操作后应当可以得到最短路径。如果有负权回路,那么第n次松弛操作仍然会成功,Bellman-Ford算法就算利用这个性质判定负环。

//Bell-Ford可以处理路径权值为负数时的单源最短路径问题,时间复杂度为o(n*m).
//根据HDU1874
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxn 1010
#define INF 0x3f3f3f3f
int n,m,a,b,c,s,e,sum,k,k1;
int map[maxn][maxn],pre[maxn],dist[maxn],lj[maxn];
struct stu
{
     int from,to,w;
}p[maxn];

void add(int x,int y,int w)
{
     p[sum].from=x;
     p[sum].to=y;
     p[sum++].w=w;
}

void bellman(int s,int e)
{
     for(int i=0;i<=n;i++)
     {
       dist[i]=INF;
       pre[i]=s;
     }
     pre[s]=-1;
     dist[s]=0;
     for(int i=0;i<n-1;i++)
     {
          for(int j=0;j<sum;j++)
          {
               int u=p[j].from;
               int v=p[j].to;
               int w=p[j].w;
               if(dist[v]>dist[u]+w)
               {
                    dist[v]=dist[u]+w;
                    pre[v]=u;
               }
          }
     }
//          for(int j=0;j<sum;j++)
//           {
//            int u=edge[j].from;
//            int v=edge[j].to;
//            int w=edge[j].w;
//            if(dist[u]>dist[u]+w)
//             return false;
//           }
//            return true;
}
int main()
{
     while(scanf("%d%d",&n,&m)!=EOF)
     {
          for(int i=0;i<=n;i++)
          for(int j=0;j<=n;j++)
          map[i][j]=map[j][i]=INF;
          memset(lj,0,sizeof(lj));
          sum=0;
          for(int i=0;i<m;i++)
          {
               scanf("%d%d%d",&a,&b,&c);
               if(c<map[a][b])
               {
                    map[a][b]=map[b][a]=c;
                    add(a,b,c);
                    add(b,a,c);
               }
          }
          scanf("%d%d",&s,&e);
          bellman(s,e);
          k=e;
          k1=0;
          lj[k1++]=e;
          while(pre[k]!=-1)
          {
               lj[k1++]=pre[k];
               k=pre[k];

          }

          printf("%d",s);
          for(int i=k1-2;i>=0;i--)
          printf("->%d",lj[i]);
          printf("\n");

          if(dist[e]==INF)
          printf("-1\n");
          else
          printf("%d\n",dist[e]);
     }
     return 0;
}
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/lyysr/article/details/46867273
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞