顾名思义,有上下界的网络流与一般网络流相比多一个下界的限制,就是一条边的流量要满足在\([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;
}
#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;
}
#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;
}
标签:int,sum,网络,下界,ss,addedge,汇有
From: https://www.cnblogs.com/z-2-we/p/18225229