Floyd-Warshall算法正確性證明


以下所有討論,都是基於有向無負權回路的圖上的。因為這一性質,任何最短路徑都不會含有環,所以也不討論路徑中包含環的情形!並且為避免混淆,將“最短路徑”稱為權值最小的路徑,將路徑經過的點數-1稱為路徑的長度。

先列出算法的c語言代碼實現,后面將用這段代碼來輔助證明。

int n;//從1..n共n個點
int dis[maxn][maxn];//權值鄰接矩陣
init();//初始化數據
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]);

先用比較形象的語言來簡單敘述一遍。

  • 以下“每次更新路徑”指k=k_i時內層的兩重循環,k是每次更新路徑采用的“中間點”。
  • 每個點k在被用作中間點時,相關路徑的最小權值,已經被繼承到本次更新的路徑里了。其他沒有被更新的點想通過k進行連接,就一定包含本次更新的路徑。並且后續只保留任意兩個端點間權值最小的那條路徑進行計算。
  • 因此在更新n次后,與所有點的相關路徑的最小權值,都已經更新完畢。也就是說,所有的路徑都已經考慮並更新過了。

下面是比較符號化的嚴謹證明。

  • 設共有\(1..n\)\(n\)個點,初始化所有長度為1的路徑集合為\(R\)\(x\)\(y\)的當前最小路徑權值為\(dis[x][y]\),這個最小權值對應\(R\)中的一條路徑\(x,r_1,r_2,...,y\)
  • 現在采用數學歸納法,以\(k=1..n\)進行\(n\)次路徑擴展,並更新\(R和dis[][]\)
  • \(k=1\)時,\(R\)中已經包含所有頂點兩兩連接的路徑。選取所有的路徑\(x,k和k,y\),進行連接得到\(G\{d|d=x,k,y\}\)\(R=R\cup G\),更新\(dis[][]\)
    這樣,\(R\)中就包含了:起點與終點之間(不包含起點、終點),僅含點1的所有路徑。因為沒有負權回路,所以后續更新的多次經過點1的路徑都不影響最小權值性質,並且也可以被R中去除路徑中回路部分的路徑替代(不影響其連接作用且權值更小,以下將不再討論有回路的路徑情況)。
  • 假設當\(k=1..n\)時,\(R\)中已經包含:起點與終點之間(不包含起點、終點),僅含\(1..k-1\)的所有路徑。令\(r_k=k\),選取R中的所有起點為\(k\)的路徑\(S\{d|d=x,r_1,r_2,...r_k\}\),和所有以\(k\)為終點的路徑\(T\{d|d=r_k,r_k+1,...y\}\),讓\(S\)\(T\)中的路徑兩兩連接,得到\(G\{d|d=x,...,r_k,...,y\}\)。然后令\(R=R\cup G\),更新\(dis[][]\)。這樣,\(R\)中就已經包含了:起點與終點之間(不包含起點、終點),僅含\(1..k\)的所有路徑。原假設成立。
  • 上述做法進行到\(k=n\)結束,\(R\)中就已經包含了這個圖所有的路徑連接可能。而更新\(dis[][]\)的步驟,因為所有的\(R\)中的路徑對應的\(dis[i][k]\)\(dis[k][j]\)都在之前計算過了,所以實際上每輪就只需計算\(dis[i][j]=min\{dis[i][j],dis[i][k]+dis[k][j]\}\)

在做作業的時候遇到這個算法,想起來好像一直在用但並不理解它的正確性,所以嘗試證明了一下。正好也作為我寫博客的一個開頭吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM