对于最大流与最大流等于最小割的理解
EK求最大流模板:
#include<bits/stdc++.h> using namespace std; const int N=1e3+10,M=2e4+10,INF=0x3f3f3f3f; int h[N],f[M],ne[M],e[M],idx; int n,m; int S,T; bool st[N]; int d[N]; int pre[N]; void add(int a,int b,int c) { e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++; } bool bfs() { memset(d,0,sizeof(d)); memset(st,0,sizeof(st)); memset(pre,0,sizeof(pre)); d[S]=INF; st[S]=true; queue<int>q; q.push(S); while(q.size()) { int t=q.front(); q.pop(); for(int i=h[t];~i;i=ne[i]) { int j=e[i]; if(f[i]>0&&!st[j]) { st[j]=true; d[j]=min(d[t],f[i]); pre[j]=i; if(j==T) return true; q.push(j); } } } return false; } void EK() { int r=0; while(bfs()) { r+=d[T]; for(int i=T;i!=S;i=e[pre[i]^1])//存边 { int id=pre[i]; f[id]-=d[T],f[id^1]+=d[T]; } } printf("%d\n",r); } int main() { scanf("%d%d%d%d",&n,&m,&S,&T); memset(h,-1,sizeof(h)); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,0); } EK(); return 0; }
Dinic求最大流:
#include <bits/stdc++.h> using namespace std; const int N = 10010, M = 200010, INF = 1e8; int n, m, S, T; int h[N], e[M], f[M], ne[M], idx; int q[N], d[N], cur[N];//q是队列,d是分成,cur是优化 void add(int a, int b, int c) { e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++; e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++; } int bfs() { memset(d, -1, sizeof d); int tt = 0, hh = 0; q[0] = S, d[S] = 0, cur[S] = h[S];//当前弧是第一个点 while (hh <= tt) { int t = q[hh ++ ]; for (int i = h[t]; ~i; i = ne[i]) { int ver = e[i]; if (d[ver] == -1 && f[i])//当前点没有被搜索,且流量大于0 { d[ver] = d[t] + 1; cur[ver] = h[ver]; //当前点的当前弧 if (ver == T) return true; q[++ tt] = ver; } } } return false; } int find(int u, int limit )//从原点能够流向u这个点的最大流量为limit { if (u == T) return limit;//如果已经到终点了 表示从原点到终点所能流的流量就是limit int flow = 0;//表示从u这个点开始往后流的流量是多少,dfs求,一开始是0的 //我们之前可能搜索u,可能有些路径满了,所以要将所有满的路径跳过 for (int i = cur[u]; ~i && flow < limit; i = ne[i])//如果从u到终点的总流量等于limit就没有必要再搜了,因为起点到u最多就是limit { cur[u] = i;//记录一下当前搜的弧是那个,流到第i条边,说明前面的边都流过了 int ver = e[i]; if (d[ver] == d[u] + 1 && f[i])//流到下一层,且当前弧可流 { //从当前点开始最多可以有多少流量 int t = find(ver, min(f[i], limit - flow)); if (!t) //从这个点到终点没有流量,说明是不可用的,就把这个点删掉 d[ver] = -1;//这个点到终点没有路径 f[i] -= t, f[i ^ 1] += t, flow += t; } } return flow; } int dinic() { int r = 0, flow; //判断如果有增广路并建立出分层图,然后找出所有增广路,将所有流量加起来 while (bfs()) while (flow = find(S, INF)) r += flow; return r; } int main() { cin >> n >> m >> S >> T; memset(h, -1, sizeof h); while (m -- ) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); } printf("%d\n", dinic()); return 0; }