總結一下最短路徑的弗洛伊德演算法(Floyd)
阿新 • • 發佈:2019-01-29
看了好多大牛部落格,我把弗洛伊德演算法在這裡總結一下。
弗洛伊德演算法的介紹,先參考百度百科:Floyd演算法
再來幾篇可以參考的博文:http://www.wutianqi.com/?p=1903
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
--------------------------------------------------------------------分割線-------------------------------------------------------------------------------------------------------------
現在我們有這麼一張圖:
我們要做的是求出從某一點到達任意一點的最短距離,我們先用鄰接矩陣來建圖,map[i][j]表示從i點到j點的距離,把自己到自己設為0,把自己到不了的邊初始化為無窮大,程式碼為:
最後,建好的圖可以用表格來表示://初始化 for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if(i==j) map[i][j]=0; else map[i][j]=inf; //讀入邊 for(int i=1; i<=m; i++) { scanf("%d%d%d",&t1,&t2,&t3); map[t1][t2]=t3; }
現在,我們來思考,假設我們來找一箇中轉的點,看他們的路程會不會改變,我們先以1號頂點作為中轉點最為例子,製圖:
我們發現,圖有了變化,我們怎麼判斷以1號頂點作為中轉點圖的路程是不是更短呢,我們只需要判斷map[i][1]+map[1][j]的路程是不是比map[i][j]的路程更短,就可以判斷,
程式碼為:
現在該怎麼辦呢,我們接著以2號頂點作為中轉點,很簡單程式碼修改一句就就可以:for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if(map[i][1]+map[1][j]<map[i][j]) map[i][j]=map[i][1]+map[1][j];
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(map[i][2]+map[2][j]<map[i][j])
map[i][j]=map[i][2]+map[2][j];
現在我們是不是發現了一個規律,只要不斷的遍歷每一個點,並且以每一個點作為中轉點看看它的值會不會改變,就可以得到從一個點到任意一個點的最短路徑,也就是多源最短路,這就是弗洛伊德演算法,程式碼為:
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(map[i][k]+map[k][j]<map[i][j])
map[i][j]=map[i][k]+map[k][j];
這樣就可以遍歷每個頂點,找出所有的最短路,演算法的複雜度為O(n^3).
對於我一開始提出的問題,完整的程式碼為:
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=1<<29;
int main()
{
int map[10][10],n,m,t1,t2,t3;
scanf("%d%d",&n,&m);//n表示頂點個數,m表示邊的條數
//初始化
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(i==j)
map[i][j]=0;
else
map[i][j]=inf;
//讀入邊
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
map[t1][t2]=t3;
}
//弗洛伊德(Floyd)核心語句
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(map[i][k]+map[k][j]<map[i][j])
map[i][j]=map[i][k]+map[k][j];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
printf("%10d",map[i][j]);
printf("\n");
}
return 0;
}
給出樣例:
輸入:
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
輸出:
0 2 5 4
9 0 3 4
6 8 0 1
5 7 10 0
輸出的就是我建圖的時候用的表格,可以表示任意一點到任意一點的最短距離。如果有什麼不對的地方,歡迎指正~~