前言
由於本人太菜,這裡不討論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)\)。