dinic演算法是網路流最大流的優化演算法之一,每一步對原圖進行分層,然後用dfs求增廣路。時間複雜度是o(n^2*m),dinic演算法最多被分為n個階段,每個階段包括建層次網路和尋找增廣路兩部分。
dinic演算法的思想是分階段地在層次網路中增廣。它與最短增廣路演算法不同之處是:最短增廣路每個階段執行完一次bfs增廣後,要重新啟動bfs從源點vs開始尋找另一條增廣路;而在dinic演算法中,只需一次dfs過程就可以實現多次增廣。
層次圖:
層次圖,就是把原圖中的點按照點到源的距離分「層」,只保留不同層之間的邊的圖。
演算法流程:
1、根據殘量網路計算層次圖。
2、在層次圖中使用dfs進行增廣直到不存在增廣路。
3、重複以上步驟直到無法增廣。
時間複雜度:
因為在dinic的執行過程中,每次重新分層,匯點所在的層次是嚴格遞增的,而n個點的層次圖最多有n層,所以最多重新分層n次。在同乙個層次圖中,因為每條增廣路都有乙個瓶頸,而兩次增廣的瓶頸不可能相同,所以增廣路最多m條。搜尋每一條增廣路時,前進和回溯都最多n次,所以這兩者造成的時間複雜度是o(nm);而沿著同一條邊(i,j)不可能列舉兩次,因為第一次列舉時要麼這條邊的容量已經用盡,要麼點j到匯不存在通路從而可將其從這一層次圖中刪除。綜上所述,dinic演算法時間複雜度的理論上界是o(n^2*m)。
首先對每條弧存一條反向弧,初始流量為0,當正向弧剩餘流量減少時,反向弧剩餘流量隨之增加,這樣就為每條弧提供了乙個反悔的機會,可以讓乙個流沿反向弧退回而去尋找更優的路線。對於乙個網路流圖,用bfs將圖分層,只保留每個點到下乙個層次的弧,目的是減少尋找增廣路的代價。對於每一次可行的增廣操作,用dfs的方法尋找一條由源點到匯點的路徑並獲得這條路徑的流量c。根據這條路徑修改整個圖,將所經之處正向邊流量減少c,反向邊流量增加c。如此反覆直到bfs找不到可行的增廣路線。
當前弧優化:
對於乙個節點x,當它在dfs中走到了第i條弧時,前i-1條弧到匯點的流一定已經被流滿而沒有可行的路線了。那麼當下一次再訪問x節點的時候,前i-1條弧就可以被刪掉而沒有任何意義了。所以我們可以在每次列舉節點x所連的弧時,改變列舉的起點,這樣就可以刪除起點以前的所有弧以達到優化的效果。
#include
#define inf 10000000
using
namespace
std;
int head[10005],nex[200005],tail[200005];
int cap[200005],tp=-1,dep[10005];
int fir[10005];
int n,m,s,t,a,b,v;
int dfs(int x,int now)
}return c;
}inline
bool bfs()}}
return dep[t];
}inline
void add(int x,int y,int v)
inline
int dinic()
int main()
printf("%d",dinic());
return
0;}
洛谷P3376 模板 網路最大流 Dinic模板
之前的dinic模板照著劉汝佳寫的vector然後十分鬼畜跑得奇慢無比,雖然別人這樣寫也沒慢多少但是自己的就是令人捉急。改成鄰接表之後快了三倍,雖然還是比較慢但是自己比較滿意了。雖然一開始ecnt從0開始wa了一發。之前的碼風也十分鬼畜呀縮排只縮1 2格不懂自己怎麼想的。反正今天就安心劃划水。inc...
洛谷P3376 模板 網路最大流
如題,給出乙個網路圖,以及其源點和匯點,求出其網路最大流。輸入格式 第一行包含四個正整數n m s t,分別表示點的個數 有向邊的個數 源點序號 匯點序號。接下來m行每行包含三個正整數ui vi wi,表示第i條有向邊從ui出發,到達vi,邊權為wi 即該邊最大流量為wi 輸出格式 一行,包含乙個正...
洛谷 P3376 模板 網路最大流
題目描述 如題,給出乙個網路圖,以及其源點和匯點,求出其網路最大流。輸入格式 第一行包含四個正整數n m s t,分別表示點的個數 有向邊的個數 源點序號 匯點序號。接下來m行每行包含三個正整數ui vi wi,表示第i條有向邊從ui出發,到達vi,邊權為wi 即該邊最大流量為wi 輸出格式 一行,...