最大流EK、Dinic、SAP三種演算法模板
阿新 • • 發佈:2018-12-11
EK
//Max_flow //@2018/05/02 Wednesday //EK algorithm [Edmonds Karp] O(V*E^2) O(v^2) //by Tawn #include <bits/stdc++.h> using namespace std; const int maxn = 1e3; const int INF = 0x3f3f3f3f; int n,m; //n - Vertices m - edges int pre[maxn]; //record predecesor and sign if it is visited int cap[maxn][maxn]; //record the capacity of residual network int flow[maxn]; //record the residual flow from starting vertex to current vertex queue <int> q; int bfs(int st, int ed) { memset(pre,-1,sizeof(pre)); while(!q.empty()) q.pop(); pre[st] = 0; flow[st] = INF; q.push(st); while(!q.empty()) { int t = q.front(); q.pop(); if(t == ed) break; for(int i = 1; i <= n; i++) { if(pre[i] == -1 && cap[t][i] > 0) { pre[i] = t; flow[i] = min(flow[t],cap[t][i]); q.push(i); } } } if(pre[ed] == -1) return -1; else return flow[ed]; } int EK(int st, int ed) { int res = 0; //the augmenting flow int sum = 0; //the max_flow while((res = bfs(st,ed)) != -1)//argumenting path { int k = ed; while(k != st) { int f = pre[k]; cap[f][k] -= res; cap[k][f] += res;//reversible edge k = f; } sum += res; } return sum; } int main() { int s,t,c; scanf("%d%d",&n,&m); memset(cap,0,sizeof(cap)); for(int i = 0; i < m; i++) { scanf("%d%d%d",&s,&t,&c); cap[s][t] = c; } int ans = EK(1,n); printf("%d\n",ans); return 0; }
Dinic
當前弧優化,維護一個cur陣列,放入所有的h[i]];每次dfs的時候用int &i = cur[x];
//Max_flow //@2018/05/04 Friday //Dinic O(n^2 * m) O(m*3*2) //by Tawn #include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 200 + 10; const int maxm = 200 + 10; int n,m; int l[maxn];//記錄層數 int h[maxn];//鏈式前向星 int cur[maxn]; int tot = 0; struct edge { int to; int c; int next; edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {} }es[maxm*2];//記錄邊 注意是2倍 void add_edge(int u, int v, int c) { es[tot] = edge(v,c,h[u]); h[u] = tot++; } bool bfs(int s, int t) { memset(l,0,sizeof(l)); l[s] = 1; queue <int> q; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); if(u == t) return true; for(int i = h[u]; i != -1; i = es[i].next) { int v = es[i].to; if(!l[v] && es[i].c) {l[v] = l[u] + 1; q.push(v);} } } return false; } int dfs(int x, int t, int mf) { if(x == t) return mf; int ret = 0; for(int i = cur[x]; i != -1; i = es[i].next) { if(es[i].c && l[x] == l[es[i].to] - 1) { int f = dfs(es[i].to,t,min(es[i].c,mf - ret)); es[i].c -= f; es[i^1].c += f; ret += f; if(ret == mf) return ret; } } return ret; } int dinic(int s, int t) { int ans = 0; while(bfs(s,t)) { for(int i = 0; i <= n; i++) cur[i] = h[i]; ans += dfs(s,t,INF); } return ans; } int main() { while(~scanf("%d%d",&n,&m)) { tot = 0; memset(h,-1,sizeof(h)); int u,v,c; for(int i = 0; i < m; i++) { scanf("%d%d%d",&u,&v,&c); add_edge(u,v,c); add_edge(v,u,0);//增加反向邊 } int ans = dinic(1,n); printf("%d\n",ans); } return 0; }
SAP
//Max_flow //@2018/05/04 Friday //SAP O(n^2 * m) O(m*3*2) //by Tawn #include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 200 + 10; const int maxm = 200 + 10; int n,m; int head[maxn];//鏈式前向星 int tot = 0; struct edge { int to; int c; int next; edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {} }es[maxm*2];//記錄邊 注意是2倍 void add_edge(int u, int v, int c) { es[tot] = edge(v,c,head[u]); head[u] = tot++; } int SAP(int s, int t) { int numh[maxn],h[maxn],ce[maxn],pre[maxn]; //numh 記錄gap優化的統計高度數量陣列,h 距離標號陣列,ce 當前弧,pre前驅陣列 int f, ans = 0, u, temp, neck, i; //初始化最大流為0 memset(h,0,sizeof(h)); memset(numh,0,sizeof(numh)); memset(pre,-1,sizeof(pre)); for(i = 1; i <= n; i++) ce[i] = head[i]; numh[0] = n; u = s; while(h[s] < n) { //尋找增廣路 if(u == t) { f = INF; for(i = s; i != t; i = es[ce[i]].to) { if(f > es[ce[i]].c) { neck = i; f = es[ce[i]].c; } } for(i = s; i != t; i = es[ce[i]].to) { temp = ce[i]; es[temp].c -= f; es[temp^1].c += f; } ans += f; u = neck; } //尋找可行弧 for(i = ce[u]; i != -1; i = es[i].next) if(es[i].c && h[u] == h[es[i].to] + 1) break; //尋找增廣路 if(i != -1) { ce[u] = i; pre[es[i].to] = u; u = es[i].to; } else { if(!--numh[h[u]]) break; //gap optimization ce[u] = head[u]; for(temp = n, i = head[u]; i != -1; i = es[i].next) if(es[i].c) temp = min(temp, h[es[i].to]); h[u] = temp + 1; ++numh[h[u]]; if(u != s) u = pre[u];//重標號並且從當前點前驅重新增廣 } } return ans; } int main() { while(~scanf("%d%d",&n,&m)) { tot = 0; memset(head,-1,sizeof(head)); int u,v,c; for(int i = 0; i < m; i++) { scanf("%d%d%d",&u,&v,&c); add_edge(u,v,c); add_edge(v,u,0);//增加反向邊 } int ans = SAP(1,n); printf("%d\n",ans); } return 0; }