多源最短路径问题-弗洛伊德(Floyd)算法

来源:互联网 发布:泰拉瑞亚mac存档位置 编辑:程序博客网 时间:2024/05/21 17:57

要获得带权图中任意两点之间的最短距离,可以通过多次调用求解单源最短路径的算法来实现。但Floyd算法来实现会更简单。

算法步骤:

假设图由邻接矩阵存放,通过二维数组dis[MaxN][MaxN]给出一张有向或者无向图,dis[i][j]代表i到j的距离,没有直接连通的路径的话就初始化为无限大,用代指无限大的极大数INF代替,但这里需要防止出现溢出的情况,否则在程序执行后将出现结果错误。

然后进行relax操作,任意三个节点i,j,k,若dis[i][k]+dis[k][j]<dis[i][j],就令dis[i][j]=dis[i][k]+dis[k][j],这样就完成了一次松弛,并且通过三层循环嵌套将最终求解多源最短路径的问题。时间复杂度为O(n^3)。

代码:

#define MaxN 1005#define min(a,b) a<b?a:bint dis[MaxN][MaxN];int num;long long floyd(){   for(int k=1;k<=num;k++){      for(int i=1;i<=num;i++){         for(int j=1;j<=num;j++){            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);         }      }   }}

dis数组初始情况:无向图情况dis[i][j]=dis[j][i],因为是对称矩阵如果想节约内存的话可以进行压缩,无向图的话dis[i][j]严格代表从 i 到 j 的距离,两种情况中对于 i 和 j 中没有路径直连的情况都将dis[i][j]赋值为一个极大数代表无限大表示此路不通。代码中num代表节点数量。


关于为什么仅仅只需要通过三次循环就能找到任意两个点之间的距离而不需要考虑任何次序。

原理

问题的最终解决实际上是有一个个子问题的解决而解决的,比如说某两点间的最短路径经过的节点依次是a1,a2,a3,a4,则这个问题的解决就变成了这四个节点的连通的过程(连通理解为找出了正确的最短路径,具体体现就是dis[i][j]中的值最终确定不会再发生改变了),而a1~a2,a2~a3,a3~a4一开始就是连通的,也就是说这三组节点中任意一组间的最短距离就是其初始的值就是说在整个循环中这些值都不会发生变化因为他们一开始就已经是a1~a2,a2~a3,a3~a4的最短距离了否则就会与a1~a2~a3~a4为a1到a4的最短路径的这个前提条件相矛盾,并且当k经过起点和终点以外的节点时,会将前后的两个节点连通和与前后两个节点相连通的节点连通,比如说当k=a2时,a1,a3将连通,k=a3时,a2,a4将连通,a1与a2已经连通,所以a1,a2,a3,a4都将相互连通,并且不需要考虑顺序也就是这里的k=a2在前还是k=a3在前,显然无论什么样的遍历顺序,只要k经过了a2,a3,a4一直到an-1中的所有节点,a1~a2....~an一定会被连通也就找到了a1~an的最短路径,k会遍历完全部节点,显然满足条件。

上面的a1.....an是代指,a1并不代表编号为1的节点,不要被a1误导。

也就是说在一次最外层的循环体中所有节点间最短路径的求解是同时进行的,只是说任何两对节点的最短距离出现的时间可能不同,但当循环结束完,所有的节点间的最短路径已经求出。

完整示例(hdu-2544):

#include<iostream>#include<cstring>using namespace std;#define MaxN 1005#define INF 1e9#define mem(a) memset(a,0,sizeof(a))#define min(a,b) a<b?a:blong long dis[MaxN][MaxN];int num;long long floyd(){   for(int k=1;k<=num;k++){      for(int i=1;i<=num;i++){         for(int j=1;j<=num;j++){            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);         }      }   }}int main(){   int n,a,b,c;   while(cin>>num>>n&&(num+n)){      for(int i=0;i<=num;i++){         for(int j=0;j<=num;j++){            dis[i][j]=INF;         }         dis[i][i]=0;      }      for(int i=1;i<=n;i++){         cin>>a>>b>>c;         dis[a][b]=dis[b][a]=c;      }      floyd();      cout<<dis[1][num]<<endl;   }}//虽然这是一道单源最短路问题但floyd能过




原创粉丝点击