hdu1532最大流EK與SAP演算法
阿新 • • 發佈:2019-02-07
EK是最樸素的最大流演算法了,但效率比較慢,當然程式碼也比較清晰,思路去看LRJ的白書就行了。
但是由於網上大牛總結SAP基本上是解決最大流的最標準模板了,
網上大牛說基本沒有什麼最大流能卡SAP。
EK程式碼:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 210; //小規模 不用考慮效率 #define INF 1<<20 int f[N][N];int r[N][N];int c[N][N]; int a[N];int q[N];int p[N]; int main() { int sum,s,n,m,b,t,x,v,k; while(scanf("%d%d",&n,&m)!=EOF) { memset(c,0,sizeof(c)); memset(f,0,sizeof(f)); for(int i=0;i<n;i++) { scanf("%d%d%d",&x,&b,&t); c[x][b]+=t; //注意該題有重邊 } sum=0; while(1) { s=1; int top=0;int last=0; memset(p,0,sizeof(p)); memset(a,0,sizeof(a)); memset(q,0,sizeof(q)); a[s]=INF; q[top++]=s; while(top>last) { int u=q[last++]; for(int v=1;v<=m;v++) { if(!a[v]&&c[u][v]>f[u][v]) { p[v]=u;q[top++]=v; //記錄v的父親,加入佇列 a[v]=a[u]<c[u][v]-f[u][v]?a[u]:c[u][v]-f[u][v]; //最小殘量 } } } if(!a[m]) break; //若沒有更新 說明已經不存在增廣路 for(k=m;k!=s;k=p[k]) { f[p[k]][k]+=a[m]; f[k][p[k]]+=a[m]; } sum+=a[m]; } printf("%d\n",sum); } return 0; }
SAP模板:
#include<cstdio> #include<cstring> using namespace std; const int maxn = 220; const int inf = 10000000;//不要開太大 int c[maxn][maxn]; int q[maxn], pre[maxn]; int level[maxn], gap[maxn]; int n, m; int s, t; void init_sap(){ memset(level, 1, sizeof (level)); //printf("--- %d\n", level[2]); //for(int i = 0; i <= n; i ++) level[i] = n + 310; memset(gap, 0, sizeof gap); memset(pre, -1, sizeof pre); int qs = 0, qe = 0; q[qe++] = t; level[t] = 0; gap[ level[t] ] ++; while(qs < qe){ int hd = q[qs++]; for(int i = 1; i <= n; i ++){ if(level[i] > n && c[i][hd] > 0){//level[i] >= n 也可以,why ? q[qe++] = i; level[i] = level[hd] + 1; gap[ level[i] ] ++; } } } } int find_path(int u){ for(int i = 1; i <= n; i ++) if(c[u][i] > 0 && level[u] == level[i] + 1) return i; return -1; } int relabel(int u){ int tmp = inf; for(int i = 1; i <= n; i ++) if(c[u][i] > 0 && tmp > level[i] + 1) tmp = level[i] + 1; if(tmp == inf) tmp = n; return tmp; } int sap(){ init_sap(); int flow = 0, u = s; while(level[s] <= n){ int v = find_path(u); if(v > 0){ pre[v] = u; u = v; if(u == t){ int min_flow = inf; for(int i = t; i != s; i = pre[i]) if(min_flow > c[ pre[i]][i]) min_flow = c[ pre[i]][i]; for(int i = t; i != s; i = pre[i]){ c[pre[i]][i] -= min_flow; c[i][pre[i]] += min_flow; } flow += min_flow; u = s; } }else{ if(-- gap[ level[u]] == 0) return flow; int v = relabel(u); gap[v] ++; level[u] = v; if(u != s) u = pre[u]; } } return flow; } int main(){ while(~scanf("%d%d", &m, &n)){ memset(c, 0, sizeof c); for(int i = 1; i <= m; i ++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); c[u][v] += w; } s = 1, t = n; int flow = sap(); printf("%d\n", flow); } return 0; }