• 算法:最短路径之弗洛伊德(Floyd)算法


    https://cloud.tencent.com/developer/article/1012420

    为了能讲明白弗洛伊德(Floyd)算法的主要思想,我们先来看最简单的案例。图7-7-12的左图是一个简单的3个顶点的连通网图。

    我们先定义两个二维数组D[3][3]和P[3][3], D代表顶点与顶点的最短路径权值和的矩阵。P代表对应顶点的最短路径的前驱矩阵。在未分析任何顶点之前,我们将D命名为D(-1),其实它就是初始图的邻接矩阵。将P命名为P(-1), 初始化为图中的矩阵。

    首先我们来分析,所有的顶点经过v0后到达另一顶点的最短路径。因为只有3个顶点,因此需要查看v1->v0->v2,得到

    D(-1)[1][0] + D(-1)[0][2] = 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] = 3, 同样地D(-1)[2][1] = 3, 于是就有了D(0)矩阵。因为有变化,所以P矩阵对应的P(-1)[1][2]和P(-1)[2][1]也修改为当前中转的顶点v0的下标0, 于是就有了P(0)。也就是说

    接下来,也就是在D(0)和P(0)的基础上继续处理所有顶点经过v1和v2后到达另一顶点的最短路径,得到D(1)和P(1)、D(2)和P(2)完成所有顶点到所有顶点的最短路径计算工作。

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

    代码如下(改编自《大话数据结构》):注意因为是要求所有顶点到所有顶点的最短路径,因为使用二维数组。

    #include<iostream>
    using namespace std;
    
    #define MAXEDGE 20
    #define MAXVEX 20
    #define INFINITY 65535
    
    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 MG, Patharc P, ShortPathTable D)
    {
        int v, w, k;
        for (v = 0; v < MG.numVertexes; v++)/* 初始化D与P */
        {
            for (w = 0; w < MG.numVertexes; w++)
            {
                D[v][w] = MG.arc[v][w];/* D[v][w]值即为对应点间的权值 */
                P[v][w] = w;/* 初始化P */
            }
        }
    
        for (k = 0; k < MG.numVertexes; k++)
        {
            for (v = 0; v < MG.numVertexes; v++)
            {
                for (w = 0; w < MG.numVertexes; w++)
                {
                    /* 如果经过下标为k顶点路径比原两点间路径更短 */
                    if (D[v][w] > D[v][k] + D[k][w])
                    {
                        /* 将当前两点间权值设为更小的一个 */
                        D[v][w] = D[v][k] + D[k][w];
                        P[v][w] = P[v][k];/* 路径设置为经过下标为k的顶点 */
                    }
                }
            }
        }
    }
    
    int main(void)
    {
        int v, w, k;
        MGraph MG;
        Patharc P;
        ShortPathTable D;
        CreateMGraph(&MG);
        ShortestPath_Floyd(MG, P, D);
    
        cout << "各顶点间最短路径如下: " << endl;
    
        for (v = 0; v < MG.numVertexes; v++)
        {
            for (w = v + 1; w < MG.numVertexes; w++)
            {
                cout << "v" << v << "--" << "v" << w << " weight: " << D[v][w]
                     << " Path: " << v << ' ';
                k = P[v][w];
                while (k != w)
                {
                    cout << "-> " << k << " ";
                    k = P[k][w];
                }
                cout << "-> " << w << endl;
            }
            cout << endl;
        }
    
        return 0;
    }

    输出为:

    程序中的算法代码非常简洁,即用了一个三层循环,k代表的是中转结点的下标,v代表起始结点,w代表结束终点。k = 0 ~ 8,表示针对每个顶点作为中转结点得到的计算结果,最终当k = 8时,两矩阵数据如图7-7-16所示。

    从上图我们可以看到第v2行的数值与Dijkstra算法求得的D数组的数值完全一样,都是{4, 3, 0, 3, 1, 4, 6, 8, 12 }, 而且这里是所有顶点到所有顶点的最短路径权值和都可以计算得出。那么如何由P这个路径数组得出具体的最短路径呢?以v2到v8为例,P[2][8] = 4,说明要经过顶点v4, 将4替换2,P[4][8] = 3, 说明经过v3, ......., 最终推导出最短路径为:v2->v4->v3->v6->v7->v8。

    Floyd算法使用了三层循环,故时间复杂度也为O(n^3),与Dijkstra算法一致,不过Floyd算法代码简洁,虽简洁但也不一定好懂,还是需要多加揣摩才能领会。另外,虽然我们使用的例子都是无向图的,但它们对于有向图依然有效,只不过在创建图的时候,有向图的邻接矩阵不是对称的而已。

  • 相关阅读:
    linux下安装rpc.rstatd
    myeclipse下编译jmeter2.4
    2010我最喜爱的耳机评选结果q
    HTTP/1.1 Range和ContentRange
    top命令的load average是什么意思?
    用户 'sa' 登录失败。该用户与可信 SQL Server 连接无关联。
    自定义ListBox,实现单多选切换(复选框)
    自定义水印输入框和密码框
    获取Windows Phone设备信息
    启动器和选择器学习(7)选择器之联系人信息保存
  • 原文地址:https://www.cnblogs.com/mohuishou-love/p/10272508.html
Copyright © 2020-2023  润新知