最短路最長路整理
發現很多東西不記下來過一段時間就想不明白了,先整理一部分,嗯不對的地方請路過的同學指正~
首先,最短路徑相關演算法通常依賴一個重要性質,即最短路徑的子路徑也是最短路。證明如下:
單源最短路:
1、Bellman-Fold演算法 (將權值變為相反數,可以求最長路)
陣列dis[i]]記錄從源點s到頂點i的路徑長度,初始化陣列dis[i]為正無窮, dis[s]為0;
以下操作迴圈執行至多n-1次,n為頂點數:
這是因為最短路從1到n,最多經過n-1條邊,而最上邊每一層for迴圈,實際上是求從源點出發,只經過k條邊最短路是多少,k最多n-1
對於每一條邊e(u, v),如果dis[u] + w(u, v) < dis[v],則另dis[v] = dis[u]+w(u, v)。w(u, v)為邊e(u,v)的權值;
若上述操作沒有對Distant進行更新,說明最短路徑已經查詢完畢,或者部分點不可達,跳出迴圈(用flag標記優化)。否則執行下次迴圈;
為了檢測圖中是否存在負環路,即權值之和小於0的環路。對於每一條邊e(u, v),如果存在dis[u] + w(u, v) < dis[v]的邊,則圖中存在負環路,即是說改圖無法求出單源最短路徑。否則陣列dis[n]中記錄的就是源點s到各頂點的最短路徑長度。
複雜度為O(VE),最短路可以處理負環。
2、DAG(有向無環圖) Shortest Path (可以求最長路)
因為是無環圖,可以首先進行拓撲排序,得到一個所有點的線性排列,這一步複雜度為O(V+E)
然後根據拓撲排序的次序對每一個節點進行處理:即對從該節點出發的所有邊進行鬆弛操作。總複雜度為O(V+E)
poj 3249
http://www.cnblogs.com/yanlingyin/archive/2011/11/12/2246716.html 最長路標記路徑
3、Dijkstra (不能改為最長路)
堆優化時間複雜度可為O(N*logN)
4、SPFA (權值取負,可以求最長路)
可以處理負權邊,即進隊次數超過N次為出現負環。每次從佇列中取點進行鬆弛操作。
複雜度為O(KE),一般情況下K小於等於2。
SPFA對Bellman-Ford演算法優化的關鍵之處在於意識到:只有那些在前一遍鬆弛中改變了距離估計值的點,才可能引起他們的鄰接點的距離估計值的改變
多源最短路:
1、Floyd演算法 (可以求最長路,但是有可能存在正環最長路不存在,無法判斷)
從任意節點i到任意節點j的最短路徑不外乎2種可能,1是直接從i到j,2是從i經過若干個節點k到j。所以,我們假設Dis(i,j)為節點u到節點v的最短路徑的距離,對於每一個節點k,我們檢查Dis(i,k)
+ Dis(k,j) < Dis(i,j)是否成立,如果成立,證明從i到k再到j的路徑比i直接到j的路徑短,我們便設定Dis(i,j)
= Dis(i,k) + Dis(k,j),這樣一來,當我們遍歷完所有節點k,Dis(i,j)中記錄的便是i到j的最短路徑的距離。
最開始初始化dis[i][j]為直接相連的權值
最外層的for迴圈實際上表示的是:僅利用點1到點k從i到j的最短路是多少。所以三層for迴圈都是從點1到點n
時間複雜度O(n^3),空間複雜度O(n^2)
同時還可以加入path[]陣列儲存路徑
http://blog.csdn.net/ll365594480/article/details/6792096
變形:floyd變形求最小環,這個連結講的很清楚
http://www.cnblogs.com/Yz81128/archive/2012/08/15/2640940.html
例題:poj 1734
應用:
1、最短路解決差分約束問題
可行解的求法
2、單源最短路(最樸素)
3、多元起點單源目的地:反向加邊處理
4、所有結對點最短路:fold-warshall
5、各演算法儲存最短路路徑