EK 复杂度O(V*E*E)
#define N 204 int c[N][N];//边容量 int f[N][N];//边实际流量 int pre[N];//记录增广路径 int res[N];//残余网络 queue<int> qq; void init(){ while(!qq.empty())qq.pop(); memset(c,0,sizeof(c)); memset(f,0,sizeof(f)); } int EK(int s,int t){ int i,j; int ans=0; while(1){ memset(res,0,sizeof(res)); res[s] = MAX;//源点的残留网络要置为无限大!否则下面找增广路出错 pre[s] = -1; qq.push(s); //bfs找增广路径 while(!qq.empty()){ int x = qq.front(); qq.pop(); for(i=1;i<=t;i++){ if(!res[i] && f[x][i] < c[x][i]){ qq.push(i); pre[i] = x; res[i] = min(c[x][i] - f[x][i], res[x]);//这里类似dp,如果有增广路,那么res[t]就是增广路的最小权 } } } if(res[t]==0)break;//找不到增广路就退出 int k = t; while(pre[k]!=-1){ f[pre[k]][k] += res[t];//正向边加上新的流量 f[k][pre[k]] -= res[t];//反向边要减去新的流量,反向边的作用是给程序一个后悔的机会 k = pre[k]; } ans += res[t]; } return ans; }
Dinic递归(推荐)
#define M 400 struct node { int u, v, next, cap; } edge[M*M]; int next[M], head[M], layer[M], Q[M * 2], mark[M]; int ecnt; void init(){ ecnt= 0; memset(head,-1,sizeof(head)); } void add(int u, int v, int c) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].cap = c; edge[ecnt].next = head[u]; head[u] = ecnt++; edge[ecnt].u = v; edge[ecnt].v = u; edge[ecnt].cap = 0; edge[ecnt].next = head[v]; head[v] = ecnt++; } bool BFS(int begin, int end) { int i, l, h, k, y; for (i = 0; i <= end; i++) layer[i] = -1; layer[begin] = 0; l = h = 0; Q[l++] = begin; while (h < l) { k = Q[h++]; for (i = head[k]; i != -1; i = edge[i].next) { y = edge[i].v; if (edge[i].cap > 0 && layer[y] == -1) { layer[y] = layer[k] + 1; if (y == end) return true; Q[l++] = y; } } } return false; } int DFS(int x, int exp, int end) { mark[x] = 1; if (x == end)return exp; int y, temp, i; for (i = next[x]; i != -1; i = edge[i].next, next[x] = i) { y = edge[i].v; if (edge[i].cap > 0 && layer[y] == layer[x] + 1 && !mark[y]) { if ((temp = (DFS(y, min(exp, edge[i].cap), end))) > 0) { edge[i].cap -= temp;//流完后正向流表示剩余流量 edge[i^1].cap += temp;//流完后反向流表示正向流的流量 return temp; } } } return 0; } int Dinic_flow(int begin, int end) { int i, ans = 0, flow; while (BFS(begin, end)) { for (i = 0; i <= end; i++)next[i] = head[i]; while (true) { for (i = 0; i <= end; i++) mark[i] = 0; flow = DFS(begin, INT_MAX, end); if (flow == 0)break; ans += flow; } } return ans; }
Dinic非递归 复杂度O(V^2*E)
#define N 20100 #define sta que //静态邻接表 int level[N]; int p[N],p1[N]; int ecnt; int que[N]; int n,m; struct edge{ int v,next; int c; }e[900000]; void init(){ ecnt = 0; memset(p,-1,sizeof(p)); } void insert(int u,int v,int c,int w){ e[ecnt].v = v; e[ecnt].c = c; e[ecnt].next = p[u]; p[u] = ecnt++; e[ecnt].v = u; e[ecnt].c = w; e[ecnt].next = p[v]; p[v] = ecnt++; } int Dinic(int st,int ed){ int ans = 0; int i,u,v,c; int head,rear,top; while(1){//重建层次图 memset(level,0,sizeof(level)); head = rear = 0; level[st]=1; que[rear++]=st; while(head<rear){ u = que[head++]; for(i=p[u];i!=-1;i=e[i].next){ v = e[i].v; c = e[i].c; if(c && level[v] == 0){ level[v] = level[u]+1; que[rear++]=v; } } } if(level[ed] == 0){//无增广路 break; } memcpy(p1,p,sizeof(p1)); top = -1; while(1){ if(top<0){ for(i=p1[st];i!=-1;i=e[i].next){ v = e[i].v; c = e[i].c; if(c && p1[v] != -1 && level[v] == 2)break; } if(i>=0){ sta[++top] = i; p1[st] = e[i].next; } else break; } u = e[sta[top]].v; if(u == ed){//找到一条增广路 //计算流的可改进量,并记录离源点最远的可能会组成下一条增广路径的边 int dd = MAX,index = -1; for(i=0;i<=top;i++){ if(dd>e[sta[i]].c){ dd = e[sta[i]].c; index = i; } } ans += dd; //调整残余网络 for(i=0;i<=top;i++){ //直接由上一残余网络计算当前残余网络 见导论P401 e[sta[i]].c -= dd; e[sta[i]^1].c += dd; } //回溯到路径上某个可能继续增广的顶点,若该顶点也无法增广,则回溯到前一个顶点(1) for(i=0;i<=top;i++){ if(e[sta[i]].c==0){ top = index-1; break; } } } else { for(i=p1[u];i!=-1;i = e[i].next){ v = e[i].v; c = e[i].c; if(c && p1[v]!=-1 && level[u]+1 == level[v])break; } if(i!=-1){ sta[++top] = i; p1[u] = e[i].next;//若沿着边i找到了增广路,则p1会被从新初始化;否则断定从边i出发无法到达汇点,以后搜索增广路将不再考虑此边。估可将其忽略 } else { p1[u] = -1; top--; } } } } return ans; }
SAP非递归 复杂度O(V*V*E)
#define N 440 #define M N*N #define inf 1<<30 int head[N]; struct Edge { int v,next,c; }edge[M]; int ecnt; void init(){ ecnt = 0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w) { edge[ecnt].v=v; edge[ecnt].c=w; edge[ecnt].next=head[u]; head[u]=ecnt++; edge[ecnt].v=u; edge[ecnt].c=0; edge[ecnt].next=head[v]; head[v]=ecnt++; } int sap(int s,int t,int nodenum){ //源,汇,汇点编号(非点数) int pre[N],cur[N],dis[N],gap[N]; int flow=0,aug=inf; int u; bool flag; int i,j; for(i=0;i<=nodenum;i++){ cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=nodenum; u=pre[s]=s; while(dis[s]<nodenum){ flag=0; for(j=cur[u];j!=-1;j=edge[j].next){ int v=edge[j].v; if(edge[j].c>0 && dis[u]==dis[v]+1){ flag=1; cur[u] = j; aug = min(aug,edge[j].c); pre[v]=u; u=v; if(u==t){ flow+=aug; while(u!=s){ u=pre[u]; edge[cur[u]].c -= aug; //边的正流不断减少 edge[cur[u]^1].c += aug; //反流增加 } aug=inf; } break; } } if(flag)continue; if(--gap[dis[u]] == 0)break; for(dis[u] = nodenum, j=head[u]; j!=-1; j=edge[j].next){ int v=edge[j].v; if(edge[j].c>0 && dis[v]<dis[u]){ dis[u]=dis[v]; cur[u]=j; } } dis[u]++; gap[dis[u]]++; u=pre[u]; } return flow; }
ISAP + GAP优化 复杂度O(V^2*E)
#define N 20010 #define M 500010 int n,m;//n为点数 m为边数 int h[N]; int gap[N]; int p[N],ecnt; int source,sink; struct edge{ int v; int next;//下一条边的编号 int val;//边权值 }e[M]; inline void init(){memset(p,-1,sizeof(p));ecnt=0;} //有向 inline void add1(int from,int to,int val){ e[ecnt].v=to; e[ecnt].val=val; e[ecnt].next=p[from]; p[from]=ecnt++; swap(from,to); e[ecnt].v=to; e[ecnt].val=0; e[ecnt].next=p[from]; p[from]=ecnt++; } //无向 inline void add2(int from,int to,int val){ e[ecnt].v=to; e[ecnt].val=val; e[ecnt].next=p[from]; p[from]=ecnt++; swap(from,to); e[ecnt].v=to; e[ecnt].val=val; e[ecnt].next=p[from]; p[from]=ecnt++; } inline int dfs(int pos,int cost){ if (pos==sink){ return cost; } int j,minh=n-1,lv=cost,d; for (j=p[pos];j!=-1;j=e[j].next){ int v=e[j].v,val=e[j].val; if(val>0){ if (h[v]+1==h[pos]){ if (lv<e[j].val) d=lv; else d=e[j].val; d=dfs(v,d); e[j].val-=d; e[j^1].val+=d; lv-=d; if (h[source]>=n) return cost-lv; if (lv==0) break; } if (h[v]<minh) minh=h[v]; } } if (lv==cost){ --gap[h[pos]]; if (gap[h[pos]]==0) h[source]=n; h[pos]=minh+1; ++gap[h[pos]]; } return cost-lv; } int sap(int st,int ed){ source=st; sink=ed; int ans=0; memset(gap,0,sizeof(gap)); memset(h,0,sizeof(h)); gap[st]=n; while (h[st]<n){ ans+=dfs(st,INT_MAX); } return ans; }