floyd算法是非單源最短路算法的一種;非單源即算法運行一次,可求出任意節點至任意可到達節點的最短路長度,其時間複雜度爲O(n^3)。
相較於單源算法dijkstra求最短路,floyd有更簡潔的代碼。關於dijkstra求最短路長度,請點擊這裏;如果你還想記錄dijkstra最短路的路徑,請點擊這裏。
下面有兩個問題:
1. 將任意一條通路取出拉直後就如圖一所示,我們想知道用floyd最終能否產生AD的直接通路?(直接通路即節點間有弧直接連接,非科學定義)
最初,圖中只有AB,BC,CD三條通路。如果先將C作爲中途節點,那麼由BC和CD將產生BD這條直接通路。接着再以節點B作爲中途節點,由AB和BC產生直接通路AC,由AB和BD(BD剛剛產生)會產生直接通路AD。即使打亂中途節點的順序,最終仍會獲得AD這條直接通路。
所以無論誰先作爲中途節點,只要將所有節點均作爲過中途節點之後,原本連通的節點之間一定會產生直接通路。
2. 我們想知道用floyd求出圖二的AD直接通路長度一定是從A到D的最短長度嗎?
最初,圖中有AE=5,AB=10,EC=5,BC=10,CD=10這五條直接的通路。如果先將B作爲中途節點,則通過AB和BC產生AC=20這條直接通路。再以節點C作爲中途節點,則通過EC和CD產生直接通路ED=15,通過BC和CD產生直接通路BD=20,通過AC(AC剛剛產生)和CD產生直接通路AD=30。再以節點E作爲中途節點,可由AE和EC得到直接通路AC=10(小於原有的AC=20,更新),再由AE和ED得到直接通路AD=20(小於原有的AD=30,更新)。
所以無論誰先作爲中途節點,只要將所有節點均作爲過中途節點之後,則所有直接通路的長度定是這兩個節點間的最短路長度。
下面是求圖3所有節點之間最短路長度的代碼(floyd):
#include<stdio.h>
const int INF=10000; //INF表示無窮大,這裏假設爲10000
const int N=100;
int p[N][N]; //p表示各節點間的距離,不存在路徑即爲無窮大
void floyd(int n) //n表示節點總數
{
int i,j,k;
for(k=0;k<n;k++) //k表示中途節點,每次將一節點作爲中途節點後,都需要更新所有節點之間的最短長度
{
for(i=0;i<n;i++) //i表示出發節點
{
for(j=0;j<n;j++)//j表示結束節點
{
if(p[i][j]>p[i][k]+p[k][j])
{
p[i][j]=p[i][k]+p[k][j];//如果節點i到節點j經過節點k有更短的長度,則更新
}
}
}
}
}
int main()
{
int i,j,n=5; //n表示節點總數
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
p[i][j]=i==j?0:INF;//初始化:i到j路徑爲無窮大或者i到i本身爲0
}
}
p[0][1]=10;p[0][3]=30;p[0][4]=100;p[1][2]=50;p[2][4]=50;p[3][2]=20;p[3][4]=60;//p[i][j]表示節點i到節點j的距離
floyd(n);
for(i=0;i<n;i++) //打印所有節點之間的最短路長度
{
for(j=0;j<n;j++)
{
printf(j==n-1?"%d=>%d:%-5d\n":"%d=>%d:%-5d ",i,j,p[i][j]);
}
printf("\n");
}
return 0;
}
運行結果: