有上下界的网络流

顾名思义,有上下界的网络流与一般网络流相比多一个下界的限制,就是一条边的流量要满足在\([l,r]\)这个区间内。
这里一共有三个问题:
1.无源汇有上下界可行流
2.有源汇有上下界可行流
3.有源汇有上下界最大/小流
三个问题是前后关联的。
无源汇有上下界可行流
对于一条边\(u\to v\),定义:
\(l(u,v)\)是边\(u\to v\)的下界。
\(r(u,v)\)是边\(u\to v\)的上界。
\(f(u,v)\)是边\(u\to v\)的流量。
需要满足两个条件:
1.\(\forall (u\to v)\in E,l(u,v)\le f(u,v)\le r(u,v)\)
2.\(\forall 1\le i\le n,\sum_{(u\to i)\in E} f(u,i)=\sum_{(i\to v)\in E} f(i,v)\)
\(g(u,v)=f(u,v)-l(u,v)\)\(a_i=\sum_{(i\to v)\in E} l(i,v)-\sum_{(u\to i)\in E} l(u,i)\)
所以\(a_i=\sum_{(u\to i)\in E} g(u,i)-\sum_{(i\to v)\in E} g(i,v)\)
建一个超级源点\(S\)和一个超级汇点\(T\),如果\(a_i>0\),则连一条\(i\to T\)的上界为\(a_i\)的边,如果\(a_i<0\),则连一条\(S\to i\)的上界为\(-a_i\)的边。
\(S\)\(T\)跑一个最大流,如果\(S\)的出边和\(T\)的入边都流满,则可行。
有源汇有上下界可行流
在这张图上除了\(s\)\(t\),都是满足\(\sum_{(u\to i)\in E} f(u,i)=\sum_{(i\to v)\in E} f(i,v)\)。为了让\(s\)\(t\)也满足,我们可以连一条\(t\to s\)的上界为$+\infty \(的边。这样就变成了无源汇有上下界可行流问题。 **有源汇有上下界最大/小流** 先是最大流,这里先跑一个有源汇有上下界可行流问题。将残量网络拿出来取出后加入的边\)t\to s\(,令\)A=f(t,s)\(,去掉后加入的边,再跑从\)s\(到\)t\(的最大流为\)B\(,答案为\)A+B\(。 最小流与最大流有两处不同: 1.\)B\(为从\)t\(到\)s\(的最大流。 2.答案为\)A-B$。
例题
#115. 无源汇有上下界可行流

#include<iostream>
#define INF 1000000000
using namespace std;
int kd(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-'){
			f=-1;
		}
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x=x*10+a-'0';
		a=getchar();
	}
	return x*f;
}
int n,m;
struct node{
	int to;
	int nxt;
	int val;
}edge[20810];
int head[210],tot;
void addedge(int u,int v,int w){
	edge[++tot].to=v;
	edge[tot].nxt=head[u];
	edge[tot].val=w;
	head[u]=tot;
}
int a[210];
int ans[10210];
int s,t;
int dep[210];
int shu[210];
int dui[210],he,ta;
int vis[210];
void bfs(){
	he=ta=1;
	dui[1]=t;
	vis[t]=1;
	dep[t]=0;
	shu[0]++;
	while(he<=ta){
		int u=dui[he];
		he++;
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(vis[v]==1){
				continue;
			}
			dui[++ta]=v;
			vis[v]=1;
			dep[v]=dep[u]+1;
			shu[dep[v]]++;
		} 
	}
}
int maxflow;
int dfs(int u,int flow){
	if(u==t){
		maxflow+=flow;
		return flow;
	}
	int used=0;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(dep[v]+1==dep[u]&&edge[i].val!=0){
			int zhi=dfs(v,min(edge[i].val,flow-used));
			if(zhi!=0){
				used+=zhi;
				edge[i].val-=zhi;
				edge[i%2==1?i+1:i-1].val+=zhi;
				if(used==flow){
					return used;
				}
			}
		}
	}
	shu[dep[u]]--;
	if(shu[dep[u]]==0){
		dep[s]=n+2;
	}
	dep[u]++;
	shu[dep[u]]++;
	return used;
}
int main(){
	cin>>n>>m;
	s=0,t=n+1; 
	for(int i=1;i<=m;i++){
		int u,v,l,r;
		u=kd();v=kd();l=kd();r=kd();
		ans[i]=l;
		a[u]+=l;
		a[v]-=l;
		addedge(u,v,r-l);
		addedge(v,u,0);
	}
	for(int i=1;i<=n;i++){
		if(a[i]==0){
			continue;
		}
		if(a[i]>0){
			addedge(i,t,a[i]);
			addedge(t,i,0);
		}
		else{
			addedge(s,i,-a[i]);
			addedge(i,s,0);
		}
	}
	bfs();
	while(dep[s]<n+2){
		dfs(s,INF);
	}
	int p=0;
	for(int i=2*m+1;i<=tot;i+=2){
		if(edge[i].val!=0){
			p=1;
			break;
		}
	}
	if(p==1){
		cout<<"NO"<<endl;
	}
	else{
		cout<<"YES"<<endl;
		for(int i=1;i<=m;i++){
			ans[i]+=edge[i*2].val;
			cout<<ans[i]<<endl;
		}
	}
	return 0;
}

#116. 有源汇有上下界最大流

#include<iostream>
#define int long long
#define INF 1000000000000000000
using namespace std;
int kd(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-'){
			f=-1;
		}
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x=x*10+a-'0';
		a=getchar();
	}
	return x*f;
}
int n,m,s,t;
struct node{
	int to;
	int nxt;
	int val;
}edge[20410];
int head[210],tot;
void addedge(int u,int v,int w){
	edge[++tot].to=v;
	edge[tot].nxt=head[u];
	edge[tot].val=w;
	head[u]=tot;
}
int a[210];
int ss,tt,lin;
int dep[210];
int shu[210];
int vis[210];
int dui[210],he,ta;
void bfs(){
	he=ta=1;
	dui[1]=tt;
	vis[tt]=1;
	dep[tt]=0;
	shu[0]++;
	while(he<=ta){
		int u=dui[he];
		he++;
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(vis[v]==1){
				continue;
			}
			dui[++ta]=v;
			vis[v]=1;
			dep[v]=dep[u]+1;
			shu[dep[v]]++;
		}
	}
}
int maxflow;
int dfs(int u,int flow){
	if(u==tt){
		maxflow+=flow;
		return flow;
	}
	int used=0;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(dep[v]+1==dep[u]&&edge[i].val!=0){
			int zhi=dfs(v,min(edge[i].val,flow-used));
			if(zhi!=0){
				used+=zhi;
				edge[i].val-=zhi;
				edge[i%2==1?i+1:i-1].val+=zhi;
				if(used==flow){
					return used;
				}
			}
		}
	}
	shu[dep[u]]--;
	if(shu[dep[u]]==0){
		dep[ss]=lin;
	}
	dep[u]++;
	shu[dep[u]]++;
	return used;
}
void ISAP(){
	bfs();
	while(dep[ss]<lin){
		dfs(ss,INF);
	}
}
signed main(){
	cin>>n>>m>>s>>t;
	ss=0,tt=n+1,lin=n+2;
	for(int i=1;i<=m;i++){
		int u,v,l,r;
		u=kd();v=kd();l=kd();r=kd();
		addedge(u,v,r-l);
		addedge(v,u,0);
		a[u]+=l;
		a[v]-=l;
	}
	addedge(t,s,INF);
	addedge(s,t,0);
	for(int i=1;i<=n;i++){
		if(a[i]==0){
			continue;
		}
		if(a[i]>0){
			maxflow-=a[i];
			addedge(i,tt,a[i]);
			addedge(tt,i,0);
		}
		else{
			addedge(ss,i,-a[i]);
			addedge(i,ss,0);
		}
	}
	ISAP();
	if(maxflow!=0){
		cout<<"please go home to sleep";
		return 0;
	}
	maxflow=edge[m*2+2].val;
	for(int u=ss;u<=tt;u++){
		while(head[u]>m*2){
			head[u]=edge[head[u]].nxt;
		}
	}
	for(int i=ss;i<=tt;i++){
		vis[i]=0;
		dep[i]=0;
	}
	for(int i=0;i<=lin+2;i++){
		shu[i]=0;
	}
	tot=m*2;
	ss=s,tt=t,lin=n;
	ISAP();
	cout<<maxflow;
	return 0;
}

#117. 有源汇有上下界最小流

#include<iostream>
#define int long long
#define INF 1000000000000000000
using namespace std;
int kd(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-'){
			f=-1;
		}
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x=x*10+a-'0';
		a=getchar();
	}
	return x*f;
}
int n,m,s,t;
struct node{
	int to;
	int nxt;
	int val;
}edge[2600020];
int head[500010],tot;
void addedge(int u,int v,int w){
	edge[++tot].to=v;
	edge[tot].nxt=head[u];
	edge[tot].val=w;
	head[u]=tot;
}
int a[500010];
int ss,tt,lin;
int vis[500010];
int dep[500010];
int shu[500010];
int dui[500010],he,ta;
void bfs(){
	he=ta=1;
	dui[1]=tt;
	vis[tt]=1;
	dep[tt]=0;
	shu[0]++;
	while(he<=ta){
		int u=dui[he];
		he++;
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(vis[v]==1){
				continue;
			}
			dui[++ta]=v;
			vis[v]=1;
			dep[v]=dep[u]+1;
			shu[dep[v]]++;
		}
	}
}
int maxflow;
int cur[50010];
int dfs(int u,int flow){
	if(u==tt){
		maxflow+=flow;
		return flow;
	}
	int used=0;
	for(int i=cur[u];i;cur[u]=i,i=edge[i].nxt){
		int v=edge[i].to;
		if(dep[v]+1==dep[u]&&edge[i].val!=0){
			int zhi=dfs(v,min(flow-used,edge[i].val));
			if(zhi!=0){
				used+=zhi;
				edge[i].val-=zhi;
				edge[i%2==1?i+1:i-1].val+=zhi;
				if(used==flow){
					return used;
				}
			}
		}
	}
	shu[dep[u]]--;
	if(shu[dep[u]]==0){
		dep[ss]=lin;
	}
	dep[u]++;
	shu[dep[u]]++;
	return used;
}
void ISAP(){
	bfs();
	while(dep[ss]<lin){
		if(ss==0){
			for(int i=0;i<=n+1;i++){
				cur[i]=head[i];
			}
		}
		else{
			for(int i=1;i<=n;i++){
				cur[i]=head[i];
			}
		}
		dfs(ss,INF);
	}
}
signed main(){
	cin>>n>>m>>s>>t;
	ss=0,tt=n+1,lin=n+2;
	for(int i=1;i<=m;i++){
		int u,v,l,r;
		u=kd();v=kd();l=kd();r=kd();
		addedge(u,v,r-l);
		addedge(v,u,0);
		a[u]+=l;
		a[v]-=l;
	} 
	addedge(t,s,INF);
	addedge(s,t,0);
	for(int i=1;i<=n;i++){
		if(a[i]==0){
			continue;
		}
		if(a[i]>0){
			maxflow-=a[i];
			addedge(i,tt,a[i]);
			addedge(tt,i,0);
		}
		else{
			addedge(ss,i,-a[i]);
			addedge(i,ss,0);
		}
	}
	ISAP();
	if(maxflow!=0){
		cout<<"please go home to sleep";
		return 0;
	}
	maxflow=-edge[m*2+2].val;
	for(int u=ss;u<=tt;u++){
		if(head[u]>2*m){
			head[u]=edge[head[u]].nxt;
		}
	}
	tot=2*m;
	for(int i=ss;i<=tt;i++){
		dep[i]=0;
		vis[i]=0;
	}
	for(int i=0;i<=lin+2;i++){
		shu[i]=0;
	}
	ss=t,tt=s,lin=n;
	ISAP();
	cout<<(-1)*maxflow;
	return 0;
}
posted @ 2024-05-31 20:16  zzzzzz2  阅读(4)  评论(0编辑  收藏  举报