对于最大流与最大流等于最小割的理解
参考某大佬博客:
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;
}