floyd 最短路演算法

2021-06-17 20:31:48 字數 3424 閱讀 1202

floyd最短路徑演算法**)

在圖論中經常會遇到這樣的問題,在乙個有向圖裡,求出任意兩個節點之間的最短距離。我們在離散數學、資料結構課上都遇到過這個問題,在計算機網路裡介紹網路層的時候好像也遇到過這個問題,記不請了... 但是書本上一律採取的是dijkstra演算法,通過dijkstra演算法可以求出單源最短路徑,然後逐個節點利用dijkstra演算法就可以了。不過在這裡想換換口味,採取robert floyd提出的演算法來解決這個問題。下面讓我們先把問題稍微的形式化一下:

如果有乙個矩陣d=[d(ij)],其中d(ij)>0表示i城市到j城市的距離。若i與j之間無路可通,那麼d(ij)就是無窮大。又有d(ii)=0。編寫乙個程式,通過這個距離矩陣d,把任意兩個城市之間的最短與其行徑的路徑找出來。

我們可以將問題分解,先找出最短的距離,然後在考慮如何找出對應的行進路線。如何找出最短路徑呢,這裡還是用到動態規劃的知識,對於任何乙個城市而言,i到j的最短距離不外乎存在經過i與j之間的k和不經過k兩種可能,所以可以令k=1,2,3,...,n(n是城市的數目),在檢查d(ij)與d(ik)+d(kj)的值;在此d(ik)與d(kj)分別是目前為止所知道的i到k與k到j的最短距離,因此d(ik)+d(kj)就是i到j經過k的最短距離。所以,若有d(ij)>d(ik)+d(kj),就表示從i出發經過k再到j的距離要比原來的i到j距離短,自然把i到j的d(ij)重寫為d(ik)+d(kj),每當乙個k查完了,d(ij)就是目前的i到j的最短距離。重複這一過程,最後當查完所有的k時,d(ij)裡面存放的就是i到j之間的最短距離了。所以我們就可以用三個for迴圈把問題搞定了,但是有乙個問題需要注意,那就是for迴圈的巢狀的順序:我們可能隨手就會寫出這樣的程式,但是仔細考慮的話,會發現是有問題的。

for(int i=0; i

問題出在我們太早的把i-k-j的距離確定下來了,假設一旦找到了i-p-j最短的距離後,i到j就相當處理完了,以後不會在改變了,一旦以後有使i到j的更短的距離時也不能再去更新了,所以結果一定是不對的。所以應當象下面一樣來寫程式:

for(int k=0; k

這樣作的意義在於固定了k,把所有i到j而經過k的距離找出來,然後象開頭所提到的那樣進行比較和重寫,因為k是在最外層的,所以會把所有的i到j都處理完後,才會移動到下乙個k,這樣就不會有問題了,看來多層迴圈的時候,我們一定要當心,否則很容易就弄錯了。

接下來就要看一看如何找出最短路徑所行經的城市了,這裡要用到另乙個矩陣p,它的定義是這樣的:p(ij)的值如果為p,就表示i到j的最短行經為i->...->p->j,也就是說p是i到j的最短行徑中的j之前的最後乙個城市。p矩陣的初值為p(ij)=i。有了這個矩陣之後,要找最短路徑就輕而易舉了。對於i到j而言找出p(ij),令為p,就知道了路徑i->...->p->j;再去找p(ip),如果值為q,i到p的最短路徑為i->...->q->p;再去找p(iq),如果值為r,i到q的最短路徑為i->...->r->q;所以一再反覆,到了某個p(it)的值為i時,就表示i到t的最短路徑為i->t,就會的到答案了,i到j的最短行徑為i->t->...->q->p->j。因為上述的演算法是從終點到起點的順序找出來的,所以輸出的時候要把它倒過來。

但是,如何動態的回填p矩陣的值呢?回想一下,當d(ij)>d(ik)+d(kj)時,就要讓i到j的最短路徑改為走i->...->k->...->j這一條路,但是d(kj)的值是已知的,換句話說,就是k->...->j這條路是已知的,所以k->...->j這條路上j的上乙個城市(即p(kj))也是已知的,當然,因為要改走i->...->k->...->j這一條路,j的上乙個城市正好是p(kj)。所以一旦發現d(ij)>d(ik)+d(kj),就把p(kj)存入p(ij)。

下面是具體的c**:

#include

#include

#include

#define maxsize 20

void floyd(int [maxsize], int [maxsize], int);

void display_path(int [maxsize], int [maxsize], int);

void reverse(int , int);

void readin(int [maxsize], int *);

#define maxsum(a, b) (((a) != int_max && (b) != int_max) ? \

((a) + (b)) : int_max)

void floyd(int dist[maxsize], int path[maxsize], int n)}

void display_path(int dist[maxsize], int path[maxsize], int n)

while (i != k);

reverse(chain, count);

printf("%d", chain[0]+1);

for (k = 1; k < count; k++)

printf("->%d", chain[k]+1);

printf("->%d", j+1);}}

}free(chain);}

#define swap(a, b)

void reverse(int x, int n)

void readin(int dist[maxsize], int *number)

gets(line);

sscanf(line, "%d%d%d", &origin, &dest, &length);

while (origin != 0 && dest != 0 && length != 0)

}測試程式如下所示:

int main(void)

其中readin函式規定了輸入的格式,第一列是指出有多少個城市;第二列以後每行三個數;第乙個和第二個是一條路徑的起點和終點,第三個數是路徑的長度,最後以三個0作為輸入結束條件。下面是乙個輸入的例子:

input the path information:

--------------------------------------

41 2 5

2 1 50

2 3 15

2 4 5

3 1 30

3 4 15

4 1 15

4 3 5

0 0 0

對應的輸出結果為:

origin->dest dist path

----------------------------------------------

1->2 5 1->2

1->3 15 1->2->4->3

1->4 10 1->2->4

2->1 20 2->4->1

2->3 10 2->4->3

2->4 5 2->4

3->1 30 3->1

3->2 35 3->1->2

3->4 15 3->4

4->1 15 4->1

4->2 20 4->1->2

4->3 5 4->3

最短路 Floyd演算法

1.定義概覽 floyd warshall演算法 floyd warshall algorithm 是解決任意兩點間的最短路徑的一種演算法,可以正確處理有向圖或負權的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。floyd warshall演算法的時間複雜度為o n3 空間複雜度為o n2 2.演...

最短路 Floyd演算法

floyd演算法思想 1.初始化矩陣 i,j連線則矩陣的值為邊的代價,否則為max 2.計算 i 經過 k 到 j 的最短路徑map i,j min並儲存路徑 時間複雜度 o n 3 空間複雜度 t n 2 void floyd int n n為節點數,節點從1開始 例題 include inclu...

Floyd 最短路演算法

時間複雜度 o n3 優點 適用於出現負邊權的情況 演算法描述 a.初始化 點u,v如果有邊相連,則dis u v w u v 如果不相連,則dis u v 0x7fffffff 無窮大 b.核心內容 for int k 1 k n k for int i 1 i n i for int j 1 j...