Floyd算法(最短路径)

2023-05-16

Floyd算法允许图中有带负权值的边,但不许有包含带负权值的边组成的回路。
原文转载自:梦醒潇湘love
      上一篇文章我们通过迪杰斯特拉算法解决了从某个源点到其余各顶点的最短路径问题。从循环嵌套很容易得到此算法的时间复杂度为O(n^2)。可是怎么只找到从源点到某一个特定终点的最短路径,其实这个问题和求源点到其他所有顶点的最短路径一样复杂,时间复杂度依然是O(n ^2 )。
       此时比较简单方法就是对每个顶点当作源点运行一次迪杰斯特拉算法,等于在原有算法的基础上,再来一次循环,此时整个算法的时间复杂度为O(n^3)。
       对此,我们再来学习另一个求最短路径的算法——弗洛伊德(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,于是就有了D的矩阵。因为有了变化,所以P矩阵对应的P-1[1][2]和P-1[2][1]也修改为当前中转的顶点v0的下标0,于是就有了P0。也就是说:
    --->动态规划乎
       接下来,其实也就是在D0P0的基础上,继续处理所有顶点经过v1和v2后到达另一顶点的最短路径,得到D1和P1、D2和P2完成所有顶点到所有顶点的最短路径的计算。
       首先我们针对下图的左网图准备两个矩阵D-1P-1,就是网图的邻接矩阵,初设为P[j][j] = j这样的矩阵,它主要用来存储路径。
   
    具体代码如下(C++),注意是:求所有顶点到所有顶点的最短路径,因此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。
    求最短路径的显示代码可以这样写:(C++)
    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");
        }

总体的代码如下:(C++)

    #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;
    }

引自:《大话数据结构》
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 分子量(Molar Mass)

    Molar mass Time limit 3 000 seconds An organic compound is any member of a large class of chemical compounds whose molec
  • 数数字(Digit Counting)

    Digit Counting Time limit 3 000 seconds Trung is bored with his mathematics homeworks He takes a piece of chalk and star
  • 周期串(Periodic Strings)

    周期串 Periodic Strings 如果一个字符串可以由某个长度为k的字符串重复多次得到 xff0c 则称该串以k为周期 例如 xff0c abcabcabcabc以3为周期 xff08 注意 xff0c 它也以6和12为周期 xff
  • 谜题(Puzzle)

    Puzzle Time limit 3 000 seconds Puzzle A children 39 s puzzle that was popular 30 years ago consisted of a 5x5 framewhic
  • 纵横字谜的答案(Crossword Answers)

    Crossword Answers Time limit 3 000 seconds Crossword Answers A crossword puzzle consists of a rectangular grid of black
  • DNA序列(DNA Consensus String)

    DNA Consensus String Time limit 3 000 seconds Figure 1 DNA Deoxyribonucleic Acid is the molecule which contains the gene
  • 古老的密码(Ancient Cipher)

    Ancient Cipher Time limit 3 000 seconds Ancient Roman empire had a strong governmentsystem with various departments incl
  • Java出现No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing

    原文转载自 sunny2038 的CSDN博客文章 原文地址 最近在看Java xff0c 在编译写书上一个例子时 xff0c 由于书上的代码只有一部分 xff0c 于是就自己补了一个内部类 结果编译时出现 xff1a No enclosi
  • 瑞星微开发工具下载镜像的配置方法?

    如何根据 parameter txt 建立配置表 xff1f 首先我们来看下 parameter txt 的内容 xff1a CMDLINE mtdparts 61 rk29xxnand 0x00002000 64 0x00004000 u
  • 特别困的学生(Extraordinarily Tired Students)

    Extraordinarily Tired Students Time limit 3 000 seconds When a student is too tired he can 39 t help sleeping in class e
  • 骰子涂色(Cube painting)

    Cube painting We have a machine for painting cubes It is supplied with three different colors blue red and green Each fa
  • 盒子(Box)

    Box Time limit 3 000 seconds Ivan works at a factory that produces heavy machinery He hasa simple job he knocks up woode
  • 循环小数(Repeating Decimals)

    Repeating Decimals Time limit 3 000 seconds Repeating Decimals The decimal expansion of the fraction 1 33 is wherethe is
  • 反片语(Ananagrams)

    反片语 Ananagrams 输入一些单词 xff0c 找出所有满足如下条件的单词 xff1a 该单词不能通过字母重排 xff0c 得到输入文本中的另外一个单词 在判断是否满足条件时 xff0c 字母不分大小写 xff0c 但在输出时应保留
  • 集合栈计算机(The SetStack Computer)

    The SetStack Computer Time limit 3 000 seconds 题目是这样的 xff1a 有一个专门为了集合运算而设计的 集合栈 计算机 该机器有一个初始为空的栈 xff0c 并且支持以下操作 xff1a PU
  • 代码对齐(Alignment of Code)

    Alignment of Code Time Limit 4000 2000 MS Java Others Memory Limit 32768 32768 K Java Others Total Submission s 958 Acce
  • Ducci序列(Ducci Sequence)

    Ducci Sequence Time limit 3 000 seconds A Ducci sequence is a sequence of n tuples of integers Given an n tuple of integ
  • 卡片游戏(Throwing cards away I)

    Problem B Throwing cards away I Given is an ordered deck of n cards numbered 1 to n with card 1 at the top and card n at
  • 交换学生(Foreign Exchange)

    Problem E Foreign Exchange Input standard input Output standard output Time Limit 1 second Your non profit organization
  • CAN通信物理容错测试checklist

    CAN通信物理容错测试checklist 工作项目中 xff0c 我们有时有些产品CAN总线功能 xff0c 一般情况下我们必须要满足以下几种状况的测试项才算符合要求 一 CAN H与CAN L短路 判定标准 xff1a 短接故障发生后 x

随机推荐

  • 对称轴(Symmetry)

    Symmetry Time limit 3 000 seconds The figure shown on the left is left right symmetric as it is possible to fold the she
  • 打印队列(Printer Queue)

    Printer Queue Time limit 3 000 seconds 分析 首先记录所求时间它在队列中的位置 xff0c 用一个队列存储这些任务的优先级 xff0c 同时也创建一个队列存储对应任务一开始的位置 xff0c 那么当我们
  • 更新字典(Updating a Dictionary)

    Updating a Dictionary Time Limit 1000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description In th
  • 铁轨(Rails)

    Rails Time limit 3 000 seconds Rails There is a famous railway station in PopPush City Country there is incredibly hilly
  • 矩阵链乘(Matrix Chain Multiplication)

    Matrix Chain Multiplication Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description
  • 天平(Not so Mobile)

    Not so Mobile Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Before being
  • 下落的树叶(The Falling Leaves)

    The Falling Leaves Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Each yea
  • 四分树(Quadtrees)

    Quadtrees Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description A quadtree is a r
  • 油田(Oil Deposits)

    Oil Deposits Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description The GeoSurvCom
  • Abbott的复仇(Abbott's Revenge)

    Abbott 39 s Revenge Time limit 3 000 seconds Abbott s Revenge Abbott s Revenge The 1999 World FinalsContest included a p
  • rockchip rk3568 openwrt修改根文件系统分区

    rk3568的openwrt根文件系统分区大小如何修改 xff1f 1 rootfs大小取决于rk356x config的配置 xff0c 默认CONFIG TARGET ROOTFS PARTSIZE 61 512 xff0c 如果需要修
  • 除法(Division)

    Division Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Write a program th
  • 最大乘积(Maximum Product)

    Maximum Product Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Problem D M
  • 分数拆分(Fractions Again?!)

    Fractions Again Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Problem A F
  • 二叉树(Tree Recovery)

    Tree Recovery Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Little Valent
  • 骑士的移动(Knight Moves)

    Knight Moves Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description A friend of yo
  • 单词(Play On Words)

    分析 首先需对欧拉道路有所了解 存在欧拉道路的充分条件 xff1a 对于无向图而言 xff0c 如果一个无向图是连通的 xff0c 且最多只有两个奇点 xff08 顶点的度数为奇数 xff09 xff0c 则一定存在欧拉道路 如果有两个奇点
  • 成语接龙(Idiomatic Phrases Game)

    Idiomatic Phrases Game Problem Description Tom is playing a game called Idiomatic Phrases Game An idiom consists of seve
  • DijKstra算法(单源最短路径)

    原文转载自 xff1a 梦醒潇湘love 转载原文是为了方便自己学习 xff0c 也希望能让更多读者在需要的情况下学到更多的知识 Dijkstra xff08 迪杰斯特拉 xff09 算法是典型的最短路径路由算法 xff0c 用于计算一个节
  • Floyd算法(最短路径)

    Floyd 算法允许图中有带负权值的边 xff0c 但不许有包含带负权值的边组成的回路 原文转载自 xff1a 梦醒潇湘love 上一篇文章我们通过迪杰斯特拉算法解决了从某个源点到其余各顶点的最短路径问题 从循环嵌套很容易得到此算法的时间复