图论之最短路径 弗洛伊德算法(Floyd)多源最短

图论之最短路径 弗洛伊德算法(Floyd)多源最短

一:

该算法解决的问题是对于一个图,对该图的没一对顶点vi != vj,要求求出vi与vj之间的最短路径和最短路径长度。

 

二:算法思想

正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。

Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从a到b,2是从a经过若干个节点x到b。所以,我们假设A[a][b]为节点a到节点b的最短路径的距离,对于每一个节点x,我们检查A[a][x] + A[x][b] < A[a][b]是否成立,如果成立,证明从a到x再到b的路径比a直接到b的路径短,我们便设置A[a][b]=A[a][x]+A[x][b],这样一来,当我们遍历完所有节点x,A[a][b]中记录的便是a到b的最短路径的距离。

接下来都是一段代码更简明阐述:

 for(k=0;k<n;k++)
 {
  for(i=0;i<n;i++)
  {
   for(j=0;j<n;j++)
   {
    if(k==i||k==j)
     continue;
    if(A[i][k]+A[k][j]<A[i][j])
    {
     A[i][j]=A[i][k]+A[k][j];
     path[i][j]=path[k][j];
    }
   }
  }
 }

但是这里我们要注意循环的嵌套顺序,如果把检查所有节点X放在最内层,那么结果将是不正确的,为什么呢?因为这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。

因此上段代码的循环嵌套才是正确的

 

三:算法的实现

在实现时,需要两个数组:

1:数组A:使用同一个数组A[i][j]开存放一系列的当前的A[i][j],初始时,A[i][j]=Edge[i][j],算法结束时A[i][j]就是vi与vj的最短路径长度

2:path数组:path[i][j]是从vi到vj的最短路径上顶点vj的前一个顶点的序号,主要用于路径的打印

    

 

四:具体代码

1:

void Floyd()
{
 int i,j,k;
 for(i=0;i<n;i++)
 {
  for(j=0;j<n;j++)
  {
   A[i][j]=Edge[i][j];//对A[][]初始化
   if(i!=j&&A[i][j]<INF)
    path[i][j]=i;//i到j有路径
   else
    path[i][j]=-1;//i到j无路径
  }
 }
 //从A(-1)递推到A(0)...A(n-1)
 //或者理解成依次将v0,v1.....v(n-1)作为中间顶点
 for(k=0;k<n;k++)
 {
  for(i=0;i<n;i++)
  {
   for(j=0;j<n;j++)
   {
    if(k==i||k==j)
     continue;
    if(A[i][k]+A[k][j]<A[i][j])
    {
     A[i][j]=A[i][k]+A[k][j];
     path[i][j]=path[k][j];
    }
   }
  }
 }
}

2:主函数的情况

 

 

int main()
{
 int i,j;
 int u,v,w;
 cin>>n;
 for(i=0;i<n;i++)//处理接接矩阵
 {
  for(j=0;j<n;j++)
  {
   Edge[i][j]=INF;
  }
 }
 for(i=0;i<n;i++)//方阵A的要求
 {
  Edge[i][i]=0;
 }
 while(1)
 {
  cin>>u>>v>>w;
  if(u==-1&&v==-1&&w==-1)
   break;
  Edge[u][v]=w;
 }
 Floyd();
 int shortest[MAXN];//从这开始就是为了打印路径
 for(i=0;i<n;i++)
 {
  for(j=0;j<n;j++)
  {
   if(i==j)
    continue;
   cout<<i<<"=>"<<j<<'\t'<<A[i][j];
   memset(shortest,0,sizeof(shortest));
   int k=0;
   shortest[k]=j;
   while(path[i][shortest[k]]!=i)
   {
    k++;
    shortest[k]=path[i][shortest[k-1]];
   }
   k++;
   shortest[k]=i;
  }
 }
   for(int t=k;t>0;t--)
    cout<<shortest[t]<<"->";
   cout<<shortest[0]<<endl;
  
 return 0;
}

 //求指教

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值