多源最短路——Floyd算法


Floyd算法

 問題的提出:已知一個有向網(或者無向網),對每一對定點vi!=vj,要求求出vi與vj之間的最短路徑和最短路徑的長度。

解決該問題有以下兩種方法:

(1)輪流以每一個定點為源點,重復執行Dijkstra算法或者Bellman-Ford算法n次,就可以求出每一對頂點之間的最短路徑和最短路徑的長度,總的時間復雜度為O(n^3)。

(2)采用Floyd算法,時間復雜度也是O(n^3),但是形式更為直接。

 

1.介紹

  floyd算法只有五行代碼,代碼簡單,三個for循環就可以解決問題,所以它的時間復雜度為O(n^3),可以求多源最短路問題。

2.思想:

  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的路徑短,我們便設置Dis(AB) = Dis(AX) + Dis(XB),這樣一來,當我們遍歷完所有節點X,Dis(AB)中記錄的便是A到B的最短路徑的距離。

舉個例子:已知下圖,

081029zdxxq919ttqt8tu8.png

  如現在只允許經過1號頂點,求任意兩點之間的最短路程,只需判斷e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是從i號頂點到j號頂點之間的路程。e[i][1]+e[1][j]表示的是從i號頂點先到1號頂點,再從1號頂點到j號頂點的路程之和。其中i是1~n循環,j也是1~n循環,代碼實現如下。

1 for(i=1; i<=n; i++)
2 {
3     for(j=1; j<=n; j++)
4     {
5         if ( e[i][j] > e[i][1]+e[1][j] )
6             e[i][j] = e[i][1]+e[1][j];
7     }
8 }

 

接下來繼續求在只允許經過1和2號兩個頂點的情況下任意兩點之間的最短路程。在只允許經過1號頂點時任意兩點的最短路程的結果下,再判斷如果經過2號頂點是否可以使得i號頂點到j號頂點之間的路程變得更短。即判斷e[i][2]+e[2][j]是否比e[i][j]要小,代碼實現為如下。

 1 //經過1號頂點
 2 for(i=1; i<=n; i++)
 3     for(j=1; j<=n; j++)
 4         if (e[i][j] > e[i][1]+e[1][j]) 
 5             e[i][j]=e[i][1]+e[1][j];
 6 //經過2號頂點
 7 for(i=1; i<=n; i++)
 8     for(j=1; j<=n; j++)
 9         if (e[i][j] > e[i][2]+e[2][j])  
10             e[i][j]=e[i][2]+e[2][j];

 

最后允許通過所有頂點作為中轉,代碼如下:

 1   for(k=1; k<=n; k++)///Floyd-Warshall算法核心語句
 2     {
 3         for(i=1; i<=n; i++)
 4         {
 5             for(j=1; j<=n; j++)
 6             {
 7                 if(map[i][j]>map[i][k]+map[k][j] )
 8                 {
 9                     map[i][j]=map[i][k]+map[k][j];
10                 }
11             }
12         }
13     }

這段代碼的基本思想就是:最開始只允許經過1號頂點進行中轉,接下來只允許經過1和2號頂點進行中轉……允許經過1~n號所有頂點進行中轉,求任意兩點之間的最短路程。與上面相同

 

3.代碼模板:

 1 #include <stdio.h>
 2 #define inf 0x3f3f3f3f
 3 int map[1000][1000];
 4 int main()
 5 {
 6     int k,i,j,n,m;///n表示頂點個數,m表示邊的條數
 7     scanf("%d %d",&n,&m);
 8     for(i=1; i<=n; i++)///初始化
 9     {
10         for(j=1; j<=n; j++)
11         {
12             if(i==j)
13                 map[i][j]=0;
14             else
15                 map[i][j]=inf;
16         }
17     }
18     int a,b,c;
19     for(i=1; i<=m; i++)///有向圖
20     {
21         scanf("%d %d %d",&a,&b,&c);
22         map[a][b]=c;
23     }
24     for(k=1; k<=n; k++)///Floyd-Warshall算法核心語句
25     {
26         for(i=1; i<=n; i++)
27         {
28             for(j=1; j<=n; j++)
29             {
30                 if(map[i][j]>map[i][k]+map[k][j] )
31                 {
32                     map[i][j]=map[i][k]+map[k][j];
33                 }
34             }
35         }
36     }
37     for(i=1; i<=n; i++)///輸出最終的結果,最終二維數組中存的即使兩點之間的最短距離
38     {
39         for(j=1; j<=n; j++)
40         {
41             printf("%10d",map[i][j]);
42         }
43         printf("\n");
44     }
45     return 0;
46 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM