多源最短路徑演算法:Floyd演算法

lingfunny發表於2020-05-04

前言

由於本人太菜,這裡不討論Floyd的正確性。

簡介

多源最短路徑,解決的是求從圖中任意兩點之間的最短路徑的問題。

分析

程式碼短小精悍,主要程式碼只有四行,直接放上:

for(int k=1;k<=n;++k)
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);

接下來一步一步分析這個演算法。
其實這個演算法並不難,首先要知道,dis[i][j]表示的是從點i到點j的最短路徑的長度。
仔細看這個語句:dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
其實,可以再將它放大,變成這樣:

if(dis[i][k]+dis[k][j]<dis[i][j])
    dis[i][j]=dis[i][k]+dis[k][j];

這個意思就是說,如果從點i到點k的最短路徑長度加上點k到點j的最短路徑長度比原來點i到點j的最短路徑長度短,就把原來i->j的最短路徑更新。
你可能會說:

誒你這不是i->k->j和i->j作比較嗎,如果i->a->b->j比i->k->j更短呢?

這時候,就要回顧一下我們的dis陣列的含義了。dis[i][j]只表示點i到點j的最短路徑的長度,並不是i->j的路徑的長度。也就是說,我們不關心是怎麼從i走到j的(可能是i->a->b->j,也可能是i->c->j),但是我們只想知道從i到j最短需要走多長,其實這就是dp(動態規劃)的想法了。
你可能會說:

如果到不了呢??那還怎麼算?

這就涉及到初始化的問題了。
由於是最短路徑問題,所以如果到不了,我們可以將dis[i][j]的值設為inf(無窮大)。
如果能從節點i直接走到節點j(這裡是直接走到,就是i,j有一條邊相連),就可以把dis[i][j]設為這條邊的權值。
在重新回顧一下Floyd的三重迴圈:

for(int k=1;k<=n;++k)
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
                    //...

其實這個k,就是我們不斷列舉的中轉點。如果從i到j經過中轉點k會更短,就可以更新。
時間複雜度顯而易見:\(O(n^3)\)

相關文章