P3376 【模板】网络最大流
本来不想写的,可是板子都记不住,所以写一下加深印象QAQ
考虑\(Dinic\)算法
\(1\)、\(bfs\)找增广路,当从\(i\)点可以到达\(j\)点且该条路还有流量时且\(j\)点以前没有到达过时,使\(dep_j=dep_i+1\)(\(dep\)数组初始定义为\(INF\)),若最终可以到达\(t\),进入第二步,否则直接输出答案
\(2\)、\(dfs\)算增广路的答案,若\(i\)点可以到达\(j\)点且该条路还有流量且\(dep_j=dep_i+1\)时,我们可以走该条路,若最终能到达\(t\),\(ans\)加上这条路的贡献,重复第一步操作。
\(3\)、剪枝加弧优化,枚举到\(e_i\)时代表前面的边已经贡献完毕,不会再做贡献,所以下此枚举可以从此边开始枚举,若该边权值已归零,可以打个标记,下此不枚举此边
上代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e4+50,INF=1e15;
ll n,m,s,t,ans;
ll u,v,w1;
ll h[N],e[N],ne[N],w[N],idx=1;
void add(ll a,ll b,ll c)
{
e[++idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx;
e[++idx]=a;
w[idx]=0;
ne[idx]=h[b];
h[b]=idx;
}
ll dep[N],now[N];
bool bfs()
{
for(ll i=1;i<=n;i++) dep[i]=INF;
dep[s]=1;
queue<ll> q;
q.push(s);
now[s]=h[s];
while(!q.empty())
{
ll wz=q.front();
q.pop();
for(ll i=h[wz];i;i=ne[i])
{
ll j=e[i];
if(w[i]==0) continue;//只枚举大于0的边
if(dep[j]==INF)
{
now[j]=h[j];
dep[j]=dep[wz]+1;
q.push(j);
if(j==t) return true;
}
}
}
return false;
}
ll dfs(ll wz,ll k)
{
if(wz==t) return k;
ll sum,res=0;
for(ll i=now[wz];i&&k;i=ne[i])
{
now[wz]=i;
ll j=e[i];
if(w[i]==0||dep[j]!=dep[wz]+1) continue;
sum=dfs(j,min(k,w[i]));
if(sum==0) dep[j]=INF;
res+=sum;
k-=sum;
w[i]-=sum;
w[i^1]+=sum;
}
return res;
}
int main()
{
scanf("%lld %lld %lld %lld",&n,&m,&s,&t);
for(ll i=1;i<=m;i++)
{
scanf("%lld %lld %lld",&u,&v,&w1);
add(u,v,w1);
}
while(bfs()) ans+=dfs(s,INF);
printf("%lld\n",ans);
return 0;
}