最短路径Floyd算法

前面我们介绍了单源最短路径问题的Dijkstra算法,Dijkstra算法虽然有比较好看的复杂度,但其对于有负权值的图来讲,就显得力不从心了,下面我们来介绍另一种更为广泛的最短路径问题的解法:Floyd算法

Floyd算法(弗洛伊德算法)的原理基于动态规划,比如要找出从a到b的经过{  1,2,3,...,k}这k个点的最短路径(dist(a,b,k)),我们把从a到b所经过的路径分为两部分,经过某一点x,和不经过x点;对于经过点x的情况,那么有:dist(a,b,k)=dist(a,x,k-1)+dist(x,b,k-1),不经过点x则有:dist(a,b,k)=dist(a,b,k-1);可以看出,这个原理的时间和空间复杂度均为O(n^3),但如果我们只定义一个二维数组dist(i,j)来表示从i到j的最短距离,那么就可以把空间复杂度降为O(n^2)了;具体做法就是顶点看的每一次循环,我们都拿dist(a,b)和dist(a,k)+dist(k,b)作比较,留下两种中的较小者。

 

Floyd算法的难点在于求出最短距离后,最短路径的表示。

我们用path(i,j)来表示在最短距离的前提下,从i到达j要经过的点,那么很明显,path()数组的初始化为path(i,j)=j;path(i,j)是在求dist(i,j)的过程中顺带改变的,如果图中某一点k满足dist(i,j)>dist(i,k)+dist(k,j),那么在改变dist(i,j)的值的同时(令dist(i,j)=dist(i,k)+dist(k,j)),改变path(i,j)的值(令path(i,j)=path(i,k));

void Floyd(int n)
{
    int i,j,k;
    for(i=1;i<=n;i++)
     for(j=1;j<=n;j++)
       path[i][j]=j;
    for(k=1;k<=n;k++)
      for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            int temp=dist[i][k]+dist[k][j];
            if(dist[i][j]>temp)
            {
                dist[i][j]=temp;
                path[i][j]=path[i][k];
            }
        }
}
void display_path(int a,int b)
{
    printf("From %d to %d :\n",a,b);
    printf("Path: %d",a);
    int temp=a;
    while(temp!=b)
    {
        printf("-->%d",path[temp][b]);
        temp=path[temp][b];
    }
    printf("\n");
    printf("Total distance : %d\n",dist[a][b]);
}

 

另外,path()路径还可以递归来求,代码如下:

void Floyd(int n)
{
    int i,j,k;
    for(i=1;i<=n;i++)
     for(j=1;j<=n;j++)
       path[i][j]=0;
    for(k=1;k<=n;k++)
      for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            int temp=dist[i][k]+dist[k][j];
            if(dist[i][j]>temp)
            {
                dist[i][j]=temp;
                path[i][j]=k;
            }
        }
}
void display_path(int a,int b)
{
    if(a==b)  return ;
    if(path[a][b]==0)
      printf("-->%d",b);
    else
    {
        display_path(a,path[a][b]);
        display_path(path[a][b],b);
    }
}


 

你可能感兴趣的:(最短路径Floyd算法)