上下界最小可行费用流[模板]

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int inf=1e9;
int n,m,ss,tt,s,t,s_,ans;
struct edge{
	int to,nxt,w,flow;
}d[maxn]; int head[maxn],cnt=1;
int in[maxn],dis[maxn],flow[maxn],pre[maxn],vis[maxn];
void add(int u,int v,int w,int flow){
	d[++cnt]=(edge){v,head[u],w,flow},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],-w,0},head[v]=cnt;
}
void ins(int u,int v,int l,int r,int w){
	add(u,v,w,r-l);//上界-下界才是流量
	in[u]-=l,in[v]+=l;//u需要流入l,y需要流出l 
	ans+=l*w;
}
bool spfa(int s,int t)
{
	for(int i=0;i<=tt*2;i++)	dis[i]=inf;
	queue<int>q; q.push(ss);
	dis[s]=0,flow[s]=inf;
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( !d[i].flow||dis[v]<=dis[u]+d[i].w )	continue;
			dis[v]=dis[u]+d[i].w;
			pre[v]=i; flow[v]=min( flow[u],d[i].flow );
			if( !vis[v] )	q.push( v ),vis[v]=1;
		}
	}
	return dis[t]!=inf;
}
int dinic(int s,int t)
{
	int ans=0,i;
	while( spfa(s,t) )
	{
		ans+=flow[t]*dis[t];
		int x=t;
		while( x!=s )
		{
			i=pre[x];
			d[i].flow-=flow[t],d[i^1].flow+=flow[t];
			x=d[i^1].to;
		}
	}
	return ans;
}
int main()
{
	cin >> n >> m;
	s=n*2+1,t=s+1;
	ss=t+1,tt=ss+1;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		int x; cin >> x;
		ins(s,i,0,1,x);//瞬间移动,下界0次,上界1次
		ins(i+n,t,0,1,0);
		ins(i,i+n,1,1,0);
	}
	for(int i=1;i<=m;i++)
	{
		int l,r,w;
		cin >> l >> r >> w;
		if( l>r )	swap(l,r);
		ins(l+n,r,0,1,w);
	}
	for(int i=1;i<=t;i++)
	{
		if( in[i]>0 )	add(ss,i,0,in[i]);
		else	add(i,tt,0,-in[i]);
	}
	add(t,s,0,inf);
	cout << ans+dinic(ss,tt);
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108304040