最大流SAP演算法

2021-05-21 19:46:09 字數 1418 閱讀 1178

求最大流有一種經典的演算法,就是每次找增廣路時用bfs找,保證找到的增廣路是弧數最少的,也就是所謂的edmonds-karp演算法。可以證明的是在使用最短路增廣時增廣過程不超過v*e次,每次bfs的時間都是o(e),所以edmonds-karp的時間複雜度就是o(v*e^2)。

如果能讓每次尋找增廣路時的時間複雜度降下來,那麼就能提高演算法效率了,使用距離標號的最短增廣路演算法就是這樣的。所謂距離標號,就是某個點到匯點的最少的弧的數量(另外一種距離標號是從源點到該點的最少的弧的數量,本質上沒什麼區別)。設點i的標號為d[i],那麼如果將滿足d[i]=d[j]+1的弧(i,j)叫做允許弧,且增廣時只走允許弧,那麼就可以達到「怎麼走都是最短路」的效果。每個點的初始標號可以在一開始用一次從匯點沿所有反向邊的bfs求出,實踐中可以初始設全部點的距離標號為0,問題就是如何在增廣過程中維護這個距離標號。

維護距離標號的方法是這樣的:當找增廣路過程中發現某點出發沒有允許弧時,將這個點的距離標號設為由它出發的所有弧的終點的距離標號的最小值加一。這種維護距離標號的方法的正確性我就不證了。由於距離標號的存在,由於「怎麼走都是最短路」,所以就可以採用dfs找增廣路,用乙個棧儲存當前路徑的弧即可。當某個點的距離標號被改變時,棧中指向它的那條弧肯定已經不是允許弧了,所以就讓它出棧,並繼續用棧頂的弧的端點增廣。為了使每次找增廣路的時間變成均攤o(v),還有乙個重要的優化是對於每個點儲存「當前弧」:初始時當前弧是鄰接表的第一條弧;在鄰接表中查詢時從當前弧開始查詢,找到了一條允許弧,就把這條弧設為當前弧;改變距離標號時,把當前弧重新設為鄰接表的第一條弧,還有一種在常數上有所優化的寫法是改變距離標號時把當前弧設為那條提供了最小標號的弧。當前弧的寫法之所以正確就在於任何時候我們都能保證在鄰接表中當前弧的前面肯定不存在允許弧。

還有乙個常數優化是在每次找到路徑並增廣完畢之後不要將路徑中所有的頂點退棧,而是只將瓶頸邊以及之後的邊退棧,這是借鑑了dinic演算法的思想。注意任何時候待增廣的「當前點」都應該是棧頂的點的終點。這的確只是乙個常數優化,由於當前邊結構的存在,我們肯定可以在o(n)的時間內復原路徑中瓶頸邊之前的所有邊。

優化:1.鄰接表優化:

如果頂點多的話,往往n^2存不下,這時候就要存邊:

存每條邊的出發點,終止點和價值,然後排序一下,再記錄每個出發點的位置。以後要呼叫從出發點出發的邊時候,只需要從記錄的位置開始找即可(其實可以用鍊錶)。優點是時間加快空間節省,缺點是程式設計複雜度將變大,所以在題目允許的情況下,建議使用鄰接矩陣。

2.gap優化:

如果一次重標號時,出現距離斷層,則可以證明st無可行流,此時則可以直接退出演算法。

3.當前弧優化:

為了使每次找增廣路的時間變成均攤o(v),還有乙個重要的優化是對於每個點儲存「當前弧」:初始時當前弧是鄰接表的第一條弧;在鄰接表中查詢時從當前弧開始查詢,找到了一條允許弧,就把這條弧設為當前弧;改變距離標號時,把當前弧重新設為鄰接表的第一條弧。

學過之後又看了演算法速度的比較,發現如果寫好的話sap的速度不會輸給hlpp。

最大流SAP演算法

求最大流有一種經典的演算法,就是每次找增廣路時用bfs找,保證找到的增廣路是弧數最少的,也就是所謂的edmonds karp演算法。可以證明的是在使用最短路增廣時增廣過程不超過v e次,每次bfs的時間都是o e 所以edmonds karp的時間複雜度就是o v e 2 如果能讓每次尋找增廣路時的...

最大流之sap演算法

若有向圖g v e 滿足下列條件 1 有且僅有乙個頂點s,它的入度為 0 這個頂點稱為源點。2 有且僅有乙個頂點t,它的出度為 0 這個頂點稱為匯點。3 每一條弧都有乙個非負數,叫做這條邊的容量,邊 vi vj 的容量用 cij 來表示。則此有向圖稱為網路流圖,記為 g v e c 對於網路流圖g中...

網路流最大流的sap 演算法

現在想將一些物資從s運抵t,必須經過一些中轉站。連線中轉站的是公路,每條公路都有最大運載量。每條弧代表一條公路,弧上的數表示該公路的最大運載量。最多能將多少貨物從s運抵t?這是乙個典型的網路流模型。為了解答此題,我們先了解網編流的有關定義和概論。若有向圖g v,e 滿足下列條件 1.有且僅有乙個頂點...