有上下界的网络流

这篇博客主要记录的是几个有上下界网络流的模板,不会的就自己百度吧

找了几篇写得比较好的博客(思想的话我就不赘述了,看这些就行):博客1博客2博客3

 

【无源汇有上下界可行流】

有 n 个点, m 条边,每条边 e 有一个流量下界 l 和流量上界 r,求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。如果无解,输出一行 NO;否则第一行输出 YES,之后 m 行每行一个整数,表示每条边的流量。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 1000005
#define inf 1ll<<31ll-1
using namespace std;
int n,m,s,t,ss,tt,num=1;
int v[M],w[M],next[M];
int d[N],f[N],ll[N],sum[N],first[N];
void add(int x,int y,int f)
{
	num++;
	next[num]=first[x];
	first[x]=num;
	v[num]=y;
	w[num]=f;
}
bool bfs(int start,int end)
{
	int x,y,i,j;
	memset(d,-1,sizeof(d));
	memcpy(f,first,sizeof(f));
	queue<int>q;
	q.push(start);
	d[start]=0;
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(i=first[x];i;i=next[i])
		{
			y=v[i];
			if(w[i]&&d[y]==-1)
			{
				d[y]=d[x]+1;
				if(y==end)
				  return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dinic(int now,int end,int flow)
{
	if(now==end)
	  return flow;
	int x,delta,ans=0;
	for(int &i=f[now];i;i=next[i])
	{
		x=v[i];
		if(w[i]&&d[x]==d[now]+1)
		{
			delta=dinic(x,end,min(flow,w[i]));
			w[i]-=delta;
			w[i^1]+=delta;
			flow-=delta;
			ans+=delta;
			if(!flow)  break;
		}
	}
	if(flow)  d[now]=-1;
	return ans;
}
int main()
{
	int x,y,i,j,l,r;
	int ans=0,maxflow=0;
	scanf("%d%d",&n,&m);
	s=0,t=n+1;
	ss=t+1,tt=ss+1;
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d%d",&x,&y,&l,&r);
		ll[num+1]=l;
		sum[x]-=l,sum[y]+=l;
		add(x,y,r-l),add(y,x,0);
	}
	for(i=1;i<=n;++i)
	{
		if(sum[i]>0)  add(ss,i,sum[i]),add(i,ss,0),ans+=sum[i];
		if(sum[i]<0)  add(i,tt,-sum[i]),add(tt,i,0);
	}
	while(bfs(ss,tt))
	  maxflow+=dinic(ss,tt,inf);
	if(maxflow!=ans)
	{
		printf("NO");
		return 0;
	}
	printf("YES\n");
	for(i=2;i<=2*m;i+=2)
	  printf("%d\n",w[i^1]+ll[i]);
	return 0;
}

 

【有源汇有上下界最大流】

有 n 个点,m 条边,每条边 e 有一个流量下界 l 和流量上界 r,给定源点 s 与汇点 t ,求源点到汇点的最大流。如果无解,输出一行“please go home to sleep”;否则输出最大流。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 1000005
#define inf 1ll<<31ll-1
using namespace std;
int n,m,s,t,ss,tt,num=1;
int v[M],w[M],next[M];
int d[N],f[N],sum[N],first[N];
bool can[N];
void add(int x,int y,int f)
{
	num++;
	next[num]=first[x];
	first[x]=num;
	v[num]=y;
	w[num]=f;
}
bool bfs(int start,int end)
{
	int x,y,i,j;
	memset(d,-1,sizeof(d));
	memcpy(f,first,sizeof(f));
	queue<int>q;
	q.push(start);
	d[start]=0;
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(i=first[x];i;i=next[i])
		{
			y=v[i];
			if(w[i]&&d[y]==-1&&!can[y])
			{
				d[y]=d[x]+1;
				if(y==end)
				  return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dinic(int now,int end,int flow)
{
	if(now==end)
	  return flow;
	int x,delta,ans=0;
	for(int &i=f[now];i;i=next[i])
	{
		x=v[i];
		if(w[i]&&d[x]==d[now]+1&&!can[x])
		{
			delta=dinic(x,end,min(flow,w[i]));
			w[i]-=delta;
			w[i^1]+=delta;
			flow-=delta;
			ans+=delta;
			if(!flow)  break;
		}
	}
	if(flow)  d[now]=-1;
	return ans;
}
int main()
{
	int x,y,i,j,l,r;
	int ans=0,maxflow=0;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	ss=0,tt=n+1;
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d%d",&x,&y,&l,&r);
		sum[x]-=l,sum[y]+=l;
		add(x,y,r-l),add(y,x,0);
	}
	for(i=1;i<=n;++i)
	{
		if(sum[i]>0)  add(ss,i,sum[i]),add(i,ss,0),ans+=sum[i];
		if(sum[i]<0)  add(i,tt,-sum[i]),add(tt,i,0);
	}
	add(t,s,inf),add(s,t,0);
	while(bfs(ss,tt))
	  maxflow+=dinic(ss,tt,inf);
	can[ss]=false;
	can[tt]=false;
	if(maxflow!=ans)
	{
		printf("please go home to sleep");
		return 0;
	}
	maxflow=0;
	while(bfs(s,t))
	  maxflow+=dinic(s,t,inf);
	printf("%d",maxflow);
	return 0;
}

 

【有源汇有上下界最小流】

有 n 个点,m 条边,每条边 e 有一个流量下界 l 和流量上界 r,给定源点 s 与汇点 t,求源点到汇点的最小流。如果无解,输出一行“please go home to sleep”;否则输出最小流。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 1000005
#define inf 1ll<<31ll-1
using namespace std;
int n,m,s,t,ss,tt,num=1;
int v[M],w[M],next[M];
int d[N],f[N],sum[N],first[N];
bool can[N];
void add(int x,int y,int f)
{
	num++;
	next[num]=first[x];
	first[x]=num;
	v[num]=y;
	w[num]=f;
}
bool bfs(int start,int end)
{
	int x,y,i,j;
	memset(d,-1,sizeof(d));
	memcpy(f,first,sizeof(f));
	queue<int>q;
	q.push(start);
	d[start]=0;
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(i=first[x];i;i=next[i])
		{
			y=v[i];
			if(w[i]&&d[y]==-1&&!can[y])
			{
				d[y]=d[x]+1;
				if(y==end)
				  return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dinic(int now,int end,int flow)
{
	if(now==end)
	  return flow;
	int x,delta,ans=0;
	for(int &i=f[now];i;i=next[i])
	{
		x=v[i];
		if(w[i]&&d[x]==d[now]+1&&!can[x])
		{
			delta=dinic(x,end,min(flow,w[i]));
			w[i]-=delta;
			w[i^1]+=delta;
			flow-=delta;
			ans+=delta;
			if(!flow)  break;
		}
	}
	if(flow)  d[now]=-1;
	return ans;
}
int main()
{
	int x,y,i,j,l,r;
	int ans=0,maxflow=0;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	ss=0,tt=n+1;
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d%d",&x,&y,&l,&r);
		sum[x]-=l,sum[y]+=l;
		add(x,y,r-l),add(y,x,0);
	}
	for(i=1;i<=n;++i)
	{
		if(sum[i]>0)  add(ss,i,sum[i]),add(i,ss,0),ans+=sum[i];
		if(sum[i]<0)  add(i,tt,-sum[i]),add(tt,i,0);
	}
	add(t,s,inf),add(s,t,0);
	while(bfs(ss,tt))
	  maxflow+=dinic(ss,tt,inf);
	can[ss]=false;
	can[tt]=false;
	if(maxflow!=ans)
	{
		printf("please go home to sleep");
		return 0;
	}
	int minflow=0;
	add(t,s,-inf),add(s,t,0);
	while(bfs(t,s))
	  minflow-=dinic(t,s,inf);
	printf("%d",minflow);
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值