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;
}
posted @ 2023-08-26 16:17  傻阙的缺  阅读(9)  评论(0编辑  收藏  举报