为了能讲明白弗洛伊德(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 这样的矩阵。主要用来存储路径。

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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
 
#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算法代码简洁,虽简洁但也不一定好懂,还是需要多加揣摩才能领会。另外,虽然我们使用的例子都是无向图的,但它们对于有向图依然有效,只不过在创建图的时候,有向图的邻接矩阵不是对称的而已。

最短路径 - 弗洛伊德(Floyd)算法的更多相关文章

  1. 图的最短路径---弗洛伊德(Floyd)算法浅析

    算法介绍 和Dijkstra算法一样,Floyd算法也是为了解决寻找给定的加权图中顶点间最短路径的算法.不同的是,Floyd可以用来解决"多源最短路径"的问题. 算法思路 算法需要 ...

  2. 数据结构与算法——弗洛伊德(Floyd)算法

    介绍 和 Dijkstra 算法一样,弗洛伊德(Floyd)算法 也是一种用于寻找给定的加权图中顶点间最短路径的算法.该算法名称以创始人之一.1978 年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特 ...

  3. C# 弗洛伊德(Floyd)算法

    弗洛伊德(Floyd)算法 主要是用于计算图中所有顶点对之间的最短距离长度的算法,如果是要求某一个特定点到图中所有顶点之间的最短距离可以用;        ;    ;    ;            ...

  4. 数据结构与算法--最短路径之Floyd算法

    数据结构与算法--最短路径之Floyd算法 我们知道Dijkstra算法只能解决单源最短路径问题,且要求边上的权重都是非负的.有没有办法解决任意起点到任意顶点的最短路径问题呢?如果用Dijkstra算 ...

  5. [Python] 弗洛伊德(Floyd)算法求图的直径并记录路径

    相关概念 对于一个图G=(V, E),求图中两点u, v间最短路径长度,称为图的最短路径问题.最短路径中最长的称为图的直径. 其中,求图中确定的某两点的最短路径算法,称为单源最短路径算法.求图中任意两 ...

  6. 最短路径之Floyd算法

    Floyd算法又称弗洛伊德算法,也叫做Floyd's algorithm,Roy–Warshall algorithm,Roy–Floyd algorithm, WFI algorithm. Floy ...

  7. 最短路径问题-Floyd算法

    概念 最短路径也是图的一个应用,即寻找图中某两个顶点的最短路径长度. 实际应用:例如确定某两个城市间的坐火车最短行车路线长度等. Floyd algorithm 中文名就是弗洛伊德算法. 算法思路:用 ...

  8. 最短路径问题——floyd算法

    floyd算法和之前讲的bellman算法.dijkstra算法最大的不同在于它所处理的终于不再是单源问题了,floyd可以解决任何点到点之间的最短路径问题,个人觉得floyd是最简单最好用的一种算法 ...

  9. 最短路径---Dijkstra/Floyd算法

    1.Dijkstra算法基础: 算法过程比prim算法稍微多一点步骤,但思想确实巧妙也是贪心,目的是求某个源点到目的点的最短距离,总的来说dijkstra也就是求某个源点到目的点的最短路,求解的过程也 ...

随机推荐

  1. Terrain tessellation &&Threaded Rendering Vk

    https://github.com/NVIDIAGameWorks/GraphicsSamples/tree/master/samples/es3aep-kepler/TerrainTessella ...

  2. 【Type】类型 ParameterizedType

    Type 接口[重要] Type接口完整的定义: public interface java.lang.reflect.Type { /** * Returns a string describing ...

  3. SVN jsvnadmin 安装与基本使用

    1. jsvnadmin  介绍 https://code.google.com/p/jsvnadmin/ Svn Admin是一个Java开发的管理Svn服务器的项目用户的web应用.安装好Svn服 ...

  4. JavaScript的js文件压缩和格式化工具

    JavaScriptcompressor.com这个网站可是大名鼎鼎啊.以前在找到过压缩 Javascript 代码的程序,一直在用,感觉效果不错.域名是: http://javascriptcomp ...

  5. 手写一个自己的LocalCache - 基于LinkedHashMap实现LRU

    功能目标      实现一个全局范围的LocalCache,各个业务点使用自己的Namespace对LocalCache进行逻辑分区.所以在LocalCache中进行读写採用的key为(namespa ...

  6. APP 打包測试流程 从零開始

    前言: 苹果应用打包測试一直是件令人头疼的事.尤其是第一次打包的时候,因为苹果官网是全英文性且缺少仔细的步骤指引.刚開始学习的人往往要花费非常多时间去干一件三分钟就能搞定的事. 今天我们来透彻的解说一 ...

  7. WIN7使用技巧 让电脑变身WiFi热点,让手机、笔记本共享上网,如何开启无线网络,共享无线网络

    将win7电脑变身WIFI热点,让手机.笔记本共享上网 用win7建立无线局域网,可以共享上网可以局域网游戏. 开启windows 7的隐藏功能:虚拟WIFI和SoftAP(即虚拟无线AP),就可以让 ...

  8. uni-app 如何引入全局方法或变量?

    利用Vue.prototype挂载到Vue实例上即可

  9. uni-app 如何开启sass\less处理

    开启方式:工具->插件安装->安装完成,启用即可

  10. 通过Servlet生成验证码图片(转)

    原文地址:http://www.cnblogs.com/xdp-gacl/p/3798190.html 一.BufferedImage类介绍 生成验证码图片主要用到了一个BufferedImage类, ...