# [知识点]有上下界的网络流学习笔记

### 1.无源汇有上下界可行流(也就是循环流)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 510000
const int inf=0x7fffffff;
int anti(int x){return (x&1)?(x+1):(x-1);}
char xB[(1<<15)+10],*xS=xB,*xT=xB;
register char ch=gtc;int f=1;
for(shu=0;ch<'0'||ch>'9';ch=gtc)if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';shu=(shu<<1)+(shu<<3)+ch-'0',ch=gtc);
shu*=f;
}
int n,m,T;
int up[N],down[N],tot[N];
struct haha{
int next,to,w;
}edge[N];
edge[++cnt].w=w;
edge[cnt].to=v;
}
int dep[N];
bool bfs(){
memset(dep,0,sizeof(dep));
dep[s]=1;std::queue<int> q;
q.push(s);
while(!q.empty()){
int k=q.front();q.pop();
int to=edge[i].to,w=edge[i].w;
if(!dep[to]&&w){
dep[to]=dep[k]+1;
if(to==t) return 1;
q.push(to);
}
}
}
return 0;
}
int dfs(int x,int f){
if(x==t) return f;
int temp=f;
int to=edge[i].to,w=edge[i].w;
if(temp&&dep[to]==dep[x]+1&&w){
int k=dfs(to,std::min(temp,w));
if(!k){dep[to]=0;continue;}
temp-=k;edge[i].w-=k;edge[anti(i)].w+=k;
}
}
return f-temp;
}
void work(){
int res(0);
while(bfs()) res+=dfs(s,inf);
if(res==sum){
printf("YES\n");
pos(i,1,m){
printf("%d\n",down[i]+edge[i*2].w);
}
}
else printf("NO\n");
}
void init(){
memset(edge,0,sizeof(edge));
cnt=sum=0;s=n+1;t=s+1;
}
int main(){
while(T--){
init();
pos(i,1,m){
tot[y]+=down[i];tot[x]-=down[i];
}
pos(i,1,n){
}
work();
}
return 0;
}


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

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 2010
const int inf=0x7ffffff;
int anti(int x){return (x&1)?(x+1):(x-1);}
int n,m;
int up[610000],down[600000],tot[N],sz,sz2;
struct haha{
int next,to,w;
}edge[2][600000];
int ss,tt,sum,cun[600000],ge[1000][1000];
int hmin(int x,int y){return x>y?y:x;}
void add(int u,int v,int w,int k){
edge[k][++cnt[k]].w=w;
edge[k][cnt[k]].to=v;
}
int dep[N];
bool bfs(int k){
memset(dep,0,sizeof(dep));
dep[s[k]]=1;
std::queue<int> q;q.push(s[k]);
while(!q.empty()){
int kk=q.front();q.pop();
int to=edge[k][i].to,w=edge[k][i].w;
if(!dep[to]&&w){
dep[to]=dep[kk]+1;
if(to==t[k]) return 1;
q.push(to);
}
}
}
return 0;
}
int dfs(int x,int f,int k){
if(x==t[k]) return f;
int temp=f;
int to=edge[k][i].to,w=edge[k][i].w;
if(temp&&dep[to]==dep[x]+1&&w){
int kk=dfs(to,hmin(temp,w),k);
if(!kk){dep[to]=0;continue;}
temp-=kk;edge[k][i].w-=kk;edge[k][anti(i)].w+=kk;
}
}
return f-temp;
}
int ans1;
void work(){
int res(0);
while(bfs(0)) res+=dfs(s[0],inf,0);
if(res==sum){
ans1=edge[0][sz*2].w;
pos(i,1,m){
++sz2;
}
pos(i,1,n){
++sz2;
pos(j,1,ge[i][0]){
++sz2;
}
}
while(bfs(1)) ans1+=dfs(s[1],inf,1);
printf("%d\n",ans1);
pos(i,1,cun[0]){
printf("%d\n",edge[0][cun[i]*2].w+edge[1][cun[i]*2].w+down[cun[i]]);
}
}
else printf("-1\n");
}
void init(){
memset(edge,0,sizeof(edge));
cnt[0]=cnt[1]=sz=sz2=sum=cun[0]=ans1=0;
pos(i,0,N-10) tot[i]=0;
}
signed main(){
while(scanf("%d%d",&n,&m)!=EOF){
init();
ss=n+m+1;tt=ss+2;
s[0]=s[1]=tt+1;t[0]=t[1]=tt+2;
pos(i,1,m){
++sz;scanf("%d",&down[sz]);up[sz]=inf;
tot[tt]+=down[sz];tot[n+i]-=down[sz];
}
pos(i,1,n){
scanf("%d",&ge[i][0]);
++sz;scanf("%d",&up[sz]);down[sz]=0;
tot[i]+=down[sz];tot[ss]-=down[sz];
pos(j,1,ge[i][0]){
++sz;cun[++cun[0]]=sz;
scanf("%d%d%d",&ge[i][j],&down[sz],&up[sz]);
ge[i][j]++;
tot[n+ge[i][j]]+=down[sz];tot[i]-=down[sz];
}
}
pos(i,1,tt){
}
work();
printf("\n");
}
return 0;
}


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

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 201000
const int inf=0x3fffffff;
int anti(int x){return (x&1)?(x+1):(x-1);}
char xB[(1<<15)+10],*xS=xB,*xT=xB;
register char ch=gtc;int f=1;
for(shu=0;ch<'0'||ch>'9';ch=gtc) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';shu=(shu<<1)+(shu<<3)+ch-'0',ch=gtc);
shu*=f;
}
int n;
struct haha{
int next,to,w;
}edge[2][N];
void add(int u,int v,int w,int k){
edge[k][++cnt[k]].w=w;edge[k][cnt[k]].to=v;
}
int s,t,ss,tt;
int sz,sz2,up[N],down[N],sum;
int ge[500][500];
int ans,dep[N];
bool bfs(int k,int s1,int t1){
std::queue<int> q;q.push(s1);
memset(dep,0,sizeof(dep));
dep[s1]=1;
while(!q.empty()){
int kk=q.front();q.pop();
int to=edge[k][i].to,w=edge[k][i].w;
if(!dep[to]&&w){
dep[to]=dep[kk]+1;
if(to==t1) return 1;
q.push(to);
}
}
}
return 0;
}
int dfs(int x,int t1,int f,int k){
if(x==t1) return f;
int temp=f;
int to=edge[k][i].to,w=edge[k][i].w;
if(w&&temp&&dep[to]==dep[x]+1){
int kk=dfs(to,t1,std::min(temp,w),k);
if(!kk){
dep[to]=0;continue;
}
temp-=kk;edge[k][i].w-=kk;edge[k][anti(i)].w+=kk;
}
}
return f-temp;
}
int tot[N];
void work(){
int res(0);
while(bfs(0,ss,tt)) res+=dfs(ss,tt,inf,0);
ans+=edge[0][sz*2].w;
pos(i,1,n){
}
pos(i,1,n){
pos(j,1,ge[i][0]){
}
}
while(bfs(1,t,s)) ans-=dfs(t,s,inf,1);
printf("%d\n",ans);
}
int main(){
pos(i,1,n){
}
pos(i,1,n){
pos(j,1,ge[i][0]){
tot[ge[i][j]]+=down[sz];tot[i]-=down[sz];
}
}
pos(i,1,t){
}
work();
return 0;
}


### 5.有源汇有上下界最小费用可行流

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 101000
const int inf=0x7f7f7f7f;
int anti(int x){return (x&1)?(x+1):(x-1);}
char xB[(1<<15)+10],*xS=xB,*xT=xB;
register char ch=gtc;int f=1;
for(shu=0;ch<'0'||ch>'9';ch=gtc) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';shu=(shu<<1)+(shu<<3)+ch-'0',ch=gtc);
shu*=f;
}
int n,m,ss,tt,s,t,pre;
int V[N],tot[N],up[N],down[N];
int sz,C[500][500];
struct haha{
int next,to,w,c;
}edge[N];
void add(int u,int v,int w,int c){
edge[++cnt].w=w;edge[cnt].to=v;
}
int dis[N],flag[N],from[N];
int spfa(){
pos(i,0,N-10) dis[i]=inf,flag[i]=from[i]=0;
std::queue<int> q;dis[ss]=0;flag[ss]=1;q.push(ss);
while(!q.empty()){
int k=q.front();q.pop();
int to=edge[i].to,w=edge[i].w,c=edge[i].c;
if(w&&dis[to]>dis[k]+c){
dis[to]=dis[k]+c;
if(!flag[to]){flag[to]=1;q.push(to);}
from[to]=i;
}
}
flag[k]=0;
}
return dis[tt]==inf?(-1):dis[tt];
}
int cost(){
int p=tt,f=inf;
while(p!=ss){
f=std::min(f,edge[from[p]].w);
p=edge[anti(from[p])].to;
}
p=tt;
while(p!=ss){
edge[from[p]].w-=f;
edge[anti(from[p])].w+=f;
p=edge[anti(from[p])].to;
}
return f;
}
void work(){
int res(0),l;
while(1){
l=spfa();if(l==-1) break;
res+=l*cost();
}
printf("%d\n",res);
}
int main(){
s=n*2+1,t=s+1;pre=t+1;ss=pre+1;tt=ss+1;
pos(i,1,n){
++sz;up[sz]=V[i];down[sz]=V[i];
tot[n+i]+=down[sz];tot[i]-=down[sz];
++sz;up[sz]=inf;
++sz;up[sz]=inf;
}
pos(i,1,n){
pos(j,i+1,n){
++sz;up[sz]=inf;
}
}
++sz;up[sz]=m;down[sz]=m;
tot[pre]+=down[sz];tot[s]-=down[sz];
++sz;up[sz]=inf;
pos(i,1,pre){
}
work();
return 0;
}


--------------------------------以下部分仅为YY而来，并没有打题验证OvO----------------------------------

### 这几天一直在打网络流，对于有上下界的网络流做了一次小小的总结，希望能对自己有所提升，同时希望能够帮助到别人

posted @ 2018-01-17 18:56 Hallmeow 阅读(...) 评论(...) 编辑 收藏