演算法:最短路徑之弗洛伊德(Floyd)演算法

來源:互聯網
上載者:User

為了能講明白弗洛伊德(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演算法代碼簡潔,雖簡潔但也不一定好懂,還是需要多加揣摩才能領會。另外,雖然我們使用的例子都是無向圖的,但它們對於有向圖依然有效,只不過在建立圖的時候,有向圖的鄰接矩陣不是對稱的而已。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.