1. 程式人生 > >Dinic當前弧優化 模板及教程

Dinic當前弧優化 模板及教程

一份 ati ios name 數組 spa scan n! pty

在閱讀本文前,建議先自學最大流的Ek算法。

引入

Ek的核心是執行bfs,一旦找到增廣路就停下來進行增廣。換言之,執行一遍BFS執行一遍DFS,這使得效率大大降低。於是我們可以考慮優化。

核心思路

在一次BFS中,找到的增廣路可能不止一條,這時我們可以本著“盡量少進行BFS”的想法,在一次bfs後把所有能增廣的路徑全部增廣。
具體怎麽做呢?
仍然是:
while(bfs(源點,匯點)) dfs();

每次bfs標記出每個點的“深度”,也就是距離源點的長度。我們將得到的新圖稱作分層圖。接下來我們在分層圖上進行增廣,把能增廣的路徑全部增廣。

其它部分和Ek大體相同。

關於當前弧優化

其實是一個很強的優化

每次增廣一條路後可以看做“榨幹”了這條路,既然榨幹了就沒有再增廣的可能了。但如果每次都掃描這些“枯萎的”邊是很浪費時間的。那我們就記錄一下“榨取”到那條邊了,然後下一次直接從這條邊開始增廣,就可以節省大量的時間。這就是當前弧優化

具體怎麽實現呢,先把鏈式前向星的head數組復制一份,存進cur數組,然後在cur數組中每次記錄“榨取”到哪條邊了。

Code

//by floatiy
#include<iostream>
#include
<cstdio> #include<algorithm> #include<queue> using namespace std; const int MAXN = 10000 + 5; const int MAXM = 100000 + 5; const int INF = 1e9; int n,m; int s,t;//源點 匯點 int maxflow;//答案 struct Edge { int next; int to,flow; } l[MAXM << 1]; int head[MAXN],cnt = 1; int
deep[MAXN],cur[MAXN];//deep記錄bfs分層圖每個點到源點的距離 queue <int> q; inline void add(int x,int y,int z) { cnt++; l[cnt].next = head[x]; l[cnt].to = y; l[cnt].flow = z; head[x] = cnt; return; } int min(int x,int y) { return x < y ? x : y; } int dfs(int now,int t,int lim) {//分別是當前點,匯點,當前邊上最小的流量 if(!lim || now == t) return lim;//終止條件 // cout<<"DEBUG: DFS HAS BEEN RUN!"<<endl; int flow = 0; int f; for(int i = cur[now]; i; i = l[i].next) {//註意!當前弧優化 cur[now] = i;//記錄一下榨取到哪裏了 if(deep[l[i].to] == deep[now] + 1 //誰叫你是分層圖 && (f = dfs(l[i].to,t,min(lim,l[i].flow)))) {//如果還能找到增廣路 flow += f; lim -= f; l[i].flow -= f; l[i ^ 1].flow += f;//記得處理反向邊 if(!lim) break;//沒有殘量就意味著不存在增廣路 } } return flow; } bool bfs(int s,int t) { for(int i = 1; i <= n; i++) { cur[i] = head[i];//拷貝一份head,畢竟我們還要用head deep[i] = 0x7f7f7f7f; } while(!q.empty()) q.pop();//清空隊列 其實沒有必要了 deep[s] = 0; q.push(s); while(!q.empty()) { int tmp = q.front(); q.pop(); for(int i = head[tmp]; i; i = l[i].next) { if(deep[l[i].to] > INF && l[i].flow) {//有流量就增廣 //deep我賦的初值是0x7f7f7f7f 大於 INF = 1e9) deep[l[i].to] = deep[tmp] + 1; q.push(l[i].to); } } } if(deep[t] < INF) return true; else return false; } void dinic(int s,int t) { while(bfs(s,t)) { maxflow += dfs(s,t,INF); // cout<<"DEBUG: BFS HAS BEEN RUN!"<<endl; } } int main() { cin>>n>>m;//點數邊數 cin>>s>>t; int x,y,z; for(int i = 1; i <= m; i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,0); } // cout<<"DEBUG: ADD FININSHED!"<<endl; dinic(s,t); printf("%d",maxflow); return 0; }

Dinic當前弧優化 模板及教程