最短路径弗洛伊德Floyd(超详细)

前一篇最短路径使用dijkstra算法可以求得单一源点到其余各点的最短路径。如果要求任意两点间的最短路径,则需要用到弗洛伊德算法(Floyd).

假设有向图G=(V,E)采用邻接矩阵cost存储,另外设置一个二维数组A用于存放当前顶点之间的最短路径长度,分量A[i][j]表示当前顶点vi到顶点vj的最短路径长度。弗洛伊德算法的基本思想是递推产生一个矩阵序列A0,A1,…,Ak,…,An,其中Ak[i][j]表示从顶点vi到顶点vj的路径上所经过的顶点编号不大于k 的最短路径长度。
弗洛伊德思想可用如下的表达式来描述:
      A0[i][j]=cost[i][j]           //初始化
      Ak [i][j]=min(Ak-1[i][j], Ak-1[i][k]+Ak-1[k][j])    0kn-1
如图:
    
初始时,有A0[i][j]=cost[i][j]。当求从顶点vi到顶点vj的路径上所经过的顶点编号不大于k的最短路径长度时,要分两种情况考虑:
    一种情况是该路径不经过顶点编号为k的顶点,此时该路径长度与从顶点vi到顶点vj的路径上所经过的顶点编号不大于k的最短路径长度相同;(如上图)
    另一种情况是从顶点vi到顶点vj的最短路径上经过编号为k的顶点。那么,该路径可分为两段,一段是从顶点vi到顶点vk的最短路径,另一段是从顶点vk到顶点vj的最短路径,此时最短路径长度等于这两段路径长度之和。(如上图)

最短路径弗洛伊德Floyd(超详细)_第1张图片
考虑经过顶点v1,A1[i][j]表示由vivj,经由顶点v1的最短路径。存在路径v0-v1-v2,路径长度为9,A1[0][2]改为9,path1[0][2]改为1,因此,(注意path矩阵的变化,它记录了从vi到vj经过的顶点编号,如下图path[0][2]=1,表示从v0到v2经过了v1。)
最短路径弗洛伊德Floyd(超详细)_第2张图片
考虑顶点v2,A2[i][j]表示由vivj,经由顶点v2的最短路径。存在路径v3-v2-v0,长度为4,A[3][0]改为4;存在路径v3-v2-v1,长度为4,A[3][1]改为4。存在路径v1-v2-v0,长度为7,A[1][0]改为7。将path[3][0]path[3][1]path[1][0]均改为2。因此,有:
最短路径弗洛伊德Floyd(超详细)_第3张图片
考虑顶点v3,A3[i][j]表示由vi到vj,经由顶点不大于v3的最短路径,存在路径v0-v3-v2,长度为8,而A2[0][2]=9,因此修改该值为A3[0][2]=8,path[0]2]=3。存在路径v1-v3-v2-v0,长度为6,而A2[1][0]=6,因此修改A3[1][0]=6,path[1][0]=3.存在路径v1-v3-v2,长度为3,而A2[1][2]=4,修改A3[1][2]=3,path[1][2]=3....... 以此类推, 最后求得的各顶点最短路径长度 A Path 矩阵为:

最短路径弗洛伊德Floyd(超详细)_第4张图片

0 0 路径为: 0,0 路径长度为: 0
0 1 路径为: 0,1 路径长度为: 5
0 2 路径为: 0,3,2 路径长度为: 8
0 3 路径为: 0,3 路径长度为: 7
1 0 路径为: 1,3,2,0 路径长度为: 6
1 1 路径为: 1,1 路径长度为: 0
1 2 路径为: 1,3,2 路径长度为: 3
1 3 路径为: 1,3 路径长度为: 2
2 0 路径为: 2,0 路径长度为: 3
2 1 路径为: 2,1 路径长度为: 3
2 2 路径为: 2,2 路径长度为: 0
2 3 路径为: 2,3 路径长度为: 2
3 0 路径为: 3,2,0 路径长度为: 4
3 1 路径为: 3,2,1 路径长度为: 4
3 2 路径为: 3,2 路径长度为: 1
3 3 路径为: 3,3 路径长度为: 0
完整的C语言实现,已测试

#include
#include
#define MAX_VERTEX_NUM 10 //最大顶点数
#define MAX_INT 10000 //无穷大


typedef int AdjType;
typedef struct
{
    int pi[MAX_VERTEX_NUM]; //存放v到vi的一条最短路径
    int end;
}PathType;


typedef char VType; //设顶点为字符类型




//邻接矩阵表示的图
typedef struct
{
    VType V[MAX_VERTEX_NUM]; //顶点存储空间
    AdjType A[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
}MGraph;


int path[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//v到各顶点的最短路径向量
int D[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//v到各顶点最短路径长度向量




//Floyd算法
//求网G(用邻接矩阵表示)中任意两点间最短路径
//D[][]是最短路径长度矩阵,path[][]最短路径标志矩阵
void Floyd(MGraph * G,int path[][MAX_VERTEX_NUM],int D[][MAX_VERTEX_NUM],int n)
{
    int i,j,k;
//初始化
    for(i=0;i{
        for(j=0;j{
     path[i][j]=-1;
           /* if(G->A[i][j]{
                path[i][j]=j;
            }
else
{
                path[i][j]=-1;
            }
            */
            D[i][j]=G->A[i][j];
        }
    }


//进行n次搜索
    for(k=0;k{
        for(i=0;i{
            for(j=0;j{
                if(D[i][j] > D[i][k] + D[k][j])
{
                    D[i][j]=D[i][k]+D[k][j]; //取小者
                    path[i][j]=k; //改Vi的后继
                }
            }
        }
    }
}



/*测试*/
int main()
{
    int i,j,k,v=0,n=4; //v为起点,n为顶点个数
    MGraph G;


    //初始化
    AdjType a[MAX_VERTEX_NUM][MAX_VERTEX_NUM]=
{
        {0,5,MAX_INT,7},
        {MAX_INT,0,4,2},
        {3,3,0,2},
        {MAX_INT,MAX_INT,1,0},
    };
    for(i=0;i{
        for(j=0;j{
            G.A[i][j]=a[i][j];
        }
    }


    Floyd(&G,path,D,4);
//输出每对顶点间最短路径长度及最短路径
    for(i=0;i{
        for(j=0;j{
            printf("顶点%d到顶点%d的最短长度: ",i,j);
            printf("%d\t",D[i][j]); //输出Vi到Vj的最短路径长度
            k=path[i][j]; //取路径上Vi的后续Vk
            printf("最短路径为:");
            printf("(V%d",i); //输出Vi的序号i
                //k不等于路径终点j时
while(k!=-1)
{
                    printf(",V%d",k); //输出k
                    k=path[k][j];
                        //求路径上下一顶点序号
                }
              //输出路径终点序号
                printf(",V%d)\n",j);
            }
            printf("\n");
        }


    return 0;
}

时间复杂度O(n^3)

你可能感兴趣的:(算法,C语言)