(转)最短路径Floyd算法

本文转自:https://blog.csdn.net/jack_20/article/details/78031310

Floyd算法求所有顶点到所有顶点的最短路径,时间复杂度也为O(n^3),但其算法非常简洁优雅。为了能讲明白该算法的精妙所在,先来看最简单的案例。

下图左部分是一个最简单的3个顶点连通网图。

先定义两个数组D[3][3]和P[3][3],D代表顶点到顶点的最短路径权值和的矩阵,P代表对应顶点的最小路径的前驱矩阵。在未分析任何顶点之前,我们将D命

名为D-1 ,其实它就是初始的图的邻接矩阵。将P命名为P-1 ,初始化为图中所示的矩阵。首先,我们来分析,所有的顶点经过v0后到达另一顶点的最短距离。

因为只有三个顶点,因此需要查看v1->v0->v2,得到D-1 [1][0] + D-1 [0][2] = 2 + 1 = 3。D-1 [1][2]表示的是v1->v2的权值是5,我们发现

D-1 [1][2] > D-1 [1][0] + D-1 [0][2],通俗的讲就是v1->v0->v2比直接v1->v2距离还要近。所以我们就让D-1 [1][2] = D-1 [1][0] + D-1 [0][2],同样的D-1 [2][1] = 3,

于是就有了D0 的矩阵。因为有了变化,所以P矩阵对应的P-1[1][2]和P-1[2][1]也修改为当前中转的顶点v0的下标0,于是就有了P0。也就是说:

--->动态规划乎

接下来,其实也就是在D0和P0的基础上,继续处理所有顶点经过v1和v2后到达另一顶点的最短路径,得到D1和P1、D2和P2完成所有顶点到所有顶点的最短

路径的计算。首先我们针对下图的左网图准备两个矩阵D-1和P-1,就是网图的邻接矩阵,初设为P[j][j] = j这样的矩阵,它主要用来存储路径。

具体代码如下,注意是:求所有顶点到所有顶点的最短路径,因此Pathmatirx和ShortPathTable都是二维数组。

/* Floyd算法,求网图G中各顶点v到其余顶点w的最短路径P[v][w]及带权长度D[v][w]。 */

void ShortestPath_Floyd(MGraph G, Patharc P, ShortPathTable D)

{

int v,w,k;

for(v=0; v<G.numVertexes; ++v)            /* 初始化D与P */

{

    for(w=0; w<G.numVertexes; ++w)

    {

        (*D)[v][w]=G.arc[v][w];            /* D[v][w]值即为对应点间的权值 */

        (*P)[v][w]=w;                    /* 初始化P */

    }

}

for(k=0; k<G.numVertexes; ++k)

{

    for(v=0; v<G.numVertexes; ++v)

    {

        for(w=0; w<G.numVertexes; ++w)

        {

            if ((*D)[v][w]>(*D)[v][k]+(*D)[k][w])

            {

                /* 如果经过下标为k顶点路径比原两点间路径更短 */

                (*D)[v][w]=(*D)[v][k]+(*D)[k][w];    /* 将当前两点间权值设为更小的一个 */

                (*P)[v][w]=(*P)[v][k];                /* 路径设置为经过下标为k的顶点 */

            }

        }

    }

}

}

下面介绍下详细的执行过程:

(1)程序开始运行,第4-11行就是初始化了D和P,使得它们成为 上图 的两个矩阵。从矩阵也得到,v0->v1路径权值为1,v0->v2路径权值为5,

v0->v3无边连线,所以路径权值为极大值65535。

(2)第12~25行,是算法的主循环,一共三层嵌套,k代表的就是中转顶点的下标。v代表起始顶点,w代表结束顶点。

(3)当k = 0时,也就是所有的顶点都经过v0中转,计算是否有最短路径的变化。可惜结果是,没有任何变化,如下图所示。

(4)当k = 1时,也就是所有的顶点都经过v1中转。此时,当v = 0 时,原本D[0][2] = 5,现在由于D[0][1] + D[1][2] = 4。因此由代码的的第20行,

二者取其最小值,得到D[0][2] = 4,同理可得D[0][3] = 8、D[0][4] = 6,当v = 2、3、4时,也修改了一些数据,请看下图左图中虚线框数据。

由于这些最小权值的修正,所以在路径矩阵P上,也要做处理,将它们都改为当前的P[v][k]值,见代码第21行。

(5)接下来就是k = 2,一直到8结束,表示针对每个顶点做中转得到的计算结果,当然,我们也要清楚,D0是以D-1为基础,D1是以D0为基础,

......,D8是以D7为基础的。最终,当k = 8时,两个矩阵数据如下图所示。

至此,我们的最短路径就算是完成了。可以看到矩阵第v0行的数值与迪杰斯特拉算法求得的D数组的数值是完全相同。而且这里是所有顶点到所有

顶点的最短路径权值和都可以计算出。

那么如何由P这个路径数组得出具体的最短路径呢?以v0到v8为例,从上图的右图第v8列,P[0][8]= 1,得到要经过顶点v1,然后将1取代0,得到P[1][8] = 2,

说明要经过v2,然后2取代1得到P[2][8] = 4,说明要经过v4,然后4取代2,得到P[4][8]= 3,说明要经过3,........,这样很容易就推倒出最终的最短路径值为

v0->v1->v2->v4->v3->v6->v7->v8。

求最短路径的显示代码可以这样写:

for(v=0; v<G.numVertexes; ++v)

{

    for(w=v+1; w<G.numVertexes; w++)

    {

        printf("v%d-v%d weight: %d ",v,w,D[v][w]);

        k=P[v][w];                /* 获得第一个路径顶点下标 */

        printf(" path: %d",v);    /* 打印源点 */

        while(k!=w)                /* 如果路径顶点下标不是终点 */

        {

            printf(" -> %d",k);    /* 打印路径顶点 */

            k=P[k][w];            /* 获得下一个路径顶点下标 */

        }

        printf(" -> %d\n",w);    /* 打印终点 */

    }

    printf("\n");

}

include "stdio.h"

include "stdlib.h"

include "io.h"

include "math.h"

include "time.h"

define OK 1

define ERROR 0

define TRUE 1

define FALSE 0

define MAXEDGE 20

define MAXVEX 20

define INFINITY 65535

typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */

typedef struct

{

int vexs[MAXVEX];

int arc[MAXVEX][MAXVEX];

int numVertexes, numEdges;

}MGraph;

typedef int Patharc[MAXVEX][MAXVEX];

typedef int ShortPathTable[MAXVEX][MAXVEX];

/* 构件图 */

void CreateMGraph(MGraph *G)

{

int i, j;

/* printf("请输入边数和顶点数:"); */

G->numEdges=16;

G->numVertexes=9;

for (i = 0; i < G->numVertexes; i++)/* 初始化图 */

{

    G->vexs[i]=i;

}

for (i = 0; i < G->numVertexes; i++)/* 初始化图 */

{

    for ( j = 0; j < G->numVertexes; j++)

    {

        if (i==j)

            G->arc[i][j]=0;

        else

            G->arc[i][j] = G->arc[j][i] = INFINITY;

    }

}

G->arc[0][1]=1;

G->arc[0][2]=5;

G->arc[1][2]=3;

G->arc[1][3]=7;

G->arc[1][4]=5;

G->arc[2][4]=1;

G->arc[2][5]=7;

G->arc[3][4]=2;

G->arc[3][6]=3;

G->arc[4][5]=3;

G->arc[4][6]=6;

G->arc[4][7]=9;

G->arc[5][7]=5;

G->arc[6][7]=2;

G->arc[6][8]=7;

G->arc[7][8]=4;

for(i = 0; i < G->numVertexes; i++)

{

    for(j = i; j < G->numVertexes; j++)

    {

        G->arc[j][i] =G->arc[i][j];

    }

}

}

/* Floyd算法,求网图G中各顶点v到其余顶点w的最短路径P[v][w]及带权长度D[v][w]。 */

void ShortestPath_Floyd(MGraph G, Patharc P, ShortPathTable D)

{

int v,w,k;

for(v=0; v<G.numVertexes; ++v) /* 初始化D与P */

{

    for(w=0; w<G.numVertexes; ++w)

    {

        (*D)[v][w]=G.arc[v][w];    /* D[v][w]值即为对应点间的权值 */

        (*P)[v][w]=w;                /* 初始化P */

    }

}

for(k=0; k<G.numVertexes; ++k)

{

    for(v=0; v<G.numVertexes; ++v)

    {

        for(w=0; w<G.numVertexes; ++w)

        {

            if ((*D)[v][w]>(*D)[v][k]+(*D)[k][w])

            {/* 如果经过下标为k顶点路径比原两点间路径更短 */

                (*D)[v][w]=(*D)[v][k]+(*D)[k][w];/* 将当前两点间权值设为更小的一个 */

                (*P)[v][w]=(*P)[v][k];/* 路径设置为经过下标为k的顶点 */

            }

        }

    }

}

}

int main(void)

{

int v,w,k;

MGraph G;

Patharc P;

ShortPathTable D; /* 求某点到其余各点的最短路径 */

CreateMGraph(&G);

ShortestPath_Floyd(G,&P,&D);

printf("各顶点间最短路径如下:\n");

for(v=0; v<G.numVertexes; ++v)

{

    for(w=v+1; w<G.numVertexes; w++)

    {

        printf("v%d-v%d weight: %d ",v,w,D[v][w]);

        k=P[v][w];                /* 获得第一个路径顶点下标 */

        printf(" path: %d",v);    /* 打印源点 */

        while(k!=w)                /* 如果路径顶点下标不是终点 */

        {

            printf(" -> %d",k);    /* 打印路径顶点 */

            k=P[k][w];            /* 获得下一个路径顶点下标 */

        }

        printf(" -> %d\n",w);    /* 打印终点 */

    }

    printf("\n");

}

printf("最短路径D\n");

for(v=0; v<G.numVertexes; ++v)

{

    for(w=0; w<G.numVertexes; ++w)

    {

        printf("%d\t",D[v][w]);

    }

    printf("\n");

}

printf("最短路径P\n");

for(v=0; v<G.numVertexes; ++v)

{

    for(w=0; w<G.numVertexes; ++w)

    {

        printf("%d ",P[v][w]);

    }

    printf("\n");

}

return 0;

}

原文地址:https://www.cnblogs.com/chenxuanzhen/p/9827705.html

时间: 2024-11-10 08:00:41

(转)最短路径Floyd算法的相关文章

最短路径—Floyd算法

Floyd算法 所有顶点对之间的最短路径问题是:对于给定的有向网络G=(V,E),要对G中任意两个顶点v,w(v不等于w),找出v到w的最短路径.当然我们可以n次执行DIJKSTRA算法,用FLOYD则更为直接,两种方法的时间复杂度都是一样的. 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包.Floyd-Warshall算法的时间复杂度

多源最短路径Floyd算法

多源最短路径是求图中任意两点间的最短路,采用动态规划算法,也称为Floyd算法.将顶点编号为0,1,2...n-1首先定义dis[i][j][k]为顶点 i 到 j 的最短路径,且这条路径只经过最大编号不超过k的顶点.于是我们最终要求的是dis[i][j][n-1].状态转移方程如下: dis[i][j][k]=min{dis[i][j][k-1],dis[i][k][k-1]+dis[k][j][k-1]}; 状态转移方程的解释:在计算dis[i][j][k]的时候,我们考虑 i 到 j 是否

算法基础 - 多源点最短路径(Floyd算法)

Floyd算法 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名. 思路 路径矩阵 通过一个图的权值矩阵求出它的每两点间的最短路径矩阵. 从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1):又用同样地公式由D(1)构造出D(2):--:最后又用同样的公式由D(n-1)构造出矩阵D(n).矩阵D(n

最短路径(Floyd)算法

#include <stdio.h>#include <stdlib.h> /* Floyd算法 */ #define VNUM 5#define MV 65536 int P[VNUM][VNUM];int A[VNUM][VNUM];int Matrix[VNUM][VNUM] ={    {0, 10, MV, 30, 100},    {MV, 0, 50, MV, MV},    {MV, MV, 0, MV, 10},    {MV, MV, 20, 0, 60},  

单源最短路径——Floyd算法

正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3). Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B.所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,

图论之最短路径floyd算法

Floyd算法是图论中经典的多源最短路径算法,即求任意两点之间的最短路径. 它可采用动态规划思想,因为它满足最优子结构性质,即最短路径序列的子序列也是最短路径. 举例说明最优子结构性质,上图中1号到5号的最短路径序列<1,2,4,5>,其子序列<1,2,4>也是最短路径. 在动态规划算法中,处于首要位置.且也是核心理念之一的就是状态的定义. 动态转移的基本思想可以认为是建立起某一状态和之前状态的一种转移表示. d[k][i][j]定义为"只能使用第1号到第k号点作为中间媒

最短路径——Floyd算法

如何求一张图中任意两顶点之间的最短路径长度,这里写一种最简单的算法——Floyd算法: 1 #include<stdio.h> 2 3 #define inf 9999 4 5 int main() 6 { 7 int e[10][10]; //用邻接矩阵表示图 8 printf("请输入顶点和边的数目:"); 9 int n,m; 10 scanf("%d%d",&n,&m); 11 for(int i=0;i<n;i++) 12

计算多源最短路径 ----- floyd算法

题目链接:https://vjudge.net/contest/146629#problem/L 题目描述:有n个星球,起点在第一个星球,求走遍全部星球的 到达时间和 最小值 解题过程: 记其中第 i 个星球到达第 j 个星球所需时间为 t[i][j] 进行floyd算法处理可得到第 i 个星球到达第 j 个星球所需的最小时间: for (k = 1; k <= n; k++) for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) t[i][

最短路径-Floyd算法(转载)

暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数字表示这条公路的长短.请注意这些公路是单向的.我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径.这个问题这也被称为"多源最短路径"问题. 现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储.比如1号城市到2号城市的路程为2,则设e[