【问题描述】
一个工厂每天生产若干商品,需运输到销售部门进行销售。从产地到销地要经过某些城镇,有不同的路线可以行走,每条两城镇间的公路都有一定的流量限制。为了保证公路的运营效率,每条公路都有一个容量下界,也就是至少应有多少车辆通过。每条公路还有一个容量上界,也就是最多应有多少车辆通过。请你计算,在不考虑其它车辆使用公路的前提下,如何充分利用所有的公路,使产地运输到销地的商品最多,最多能运输多少商品。
【输入格式】
输入文件有若干行
第一行,一个整数n,表示共有n个城市(2<=n<=100),产地是1号城市,销地是n号城市
下面有n行,每行有2n个数字。第p行第2q−1,2q列的数字表示城镇p与城镇q之间有无公路连接。数字为0表示无,大于0表示有公路,且这两个数字分别表示该公路流量的下界,上界。
【输出格式】
输出文件有一行
第一行,1个整数ans,表示最大流量为ans
【输入输出样例】
输入文件名: maxflowb.in
6
0 0 1 3 0 10 0 0 0 0 0 0
0 0 0 0 0 0 5 7 0 0 0 0
0 0 0 0 0 0 0 0 2 8 0 0
0 0 0 0 1 3 0 0 0 0 3 5
0 0 2 4 0 0 0 0 0 0 2 6
0 0 0 0 0 0 0 0 0 0 0 0
输出文件名:maxflowb.out
10
裸的有汇源上下界最大流
建图:
以前写的最大流默认的下界为0,而这里的下界却不为0,所以我们要进行再构造让每条边的下界为0,这样做是为了方便处理。对于每根管子有一个上界容量up和一个下界容量low,我们让这根管子的容量下界变为0,上界为up-low。可是这样做了的话流量就不守恒了,为了再次满足流量守恒,即每个节点”入流=出流”,我们增设一个超级源点st和一个超级终点sd。我们开设一个数组du[]来记录每个节点的流量情况。
du[i]=in[i](i节点所有入流下界之和)-out[i](i节点所有出流下界之和)。
当du[i]大于0的时候,st到i连一条流量为du[i]的边。
当du[i]小于0的时候,i到sd连一条流量为-du[i]的边。
最后连一条st到sd的边,容量为INF
跑最大流就行
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=100010;
const int maxm=1000010;
const int INF=1000000000;
int cnt,fir[maxn],to[maxm],nxt[maxm],cap[maxm];
int dis[maxn],gap[maxn],path[maxn],fron[maxn];
queue<int>q;
struct Net_Flow{
int tot;
void Init(int tot_){
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
memset(fir,0,sizeof(fir));
cnt=1;tot=tot_;
}
void add(int a,int b,int c){
nxt[++cnt]=fir[a];
cap[cnt]=c;
fir[a]=cnt;
to[cnt]=b;
}
void addedge(int a,int b,int c){
add(a,b,c);add(b,a,0);
}
bool BFS(int S,int T){
dis[T]=1;q.push(T);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=fir[x];i;i=nxt[i])
if(!dis[to[i]]){
dis[to[i]]=dis[x]+1;
q.push(to[i]);
}
}
return dis[S];
}
int Max_Flow(int S,int T){
if(!BFS(S,T))return 0;
for(int i=1;i<=tot;i++)fron[i]=fir[i];
for(int i=1;i<=tot;i++)gap[dis[i]]+=1;
int ret=0,p=S,f,Min;
while(dis[S]<=tot){
if(p==T){
f=INF;
while(p!=S){
f=min(f,cap[path[p]]);
p=to[path[p]^1];
}ret+=f;p=T;
while(p!=S){
cap[path[p]]-=f;
cap[path[p]^1]+=f;
p=to[path[p]^1];
}
}
for(int &i=fron[p];i;i=nxt[i])
if(cap[i]&&dis[to[i]]==dis[p]-1)
{path[p=to[i]]=i;break;}
if(!fron[p]){Min=tot;
if(--gap[dis[p]]==0)break;
for(int i=fir[p];i;i=nxt[i])
if(cap[i])Min=min(Min,dis[to[i]]);
gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
if(p!=S)p=to[path[p]^1];
}
}
//if(!Judge())ret=0;
return ret;
}
}ISAP;
int Min[110][110];
int Max[110][110];
int main(){
freopen("maxflowb.in","r",stdin);
freopen("maxflowb.out","w",stdout);
int n,S,T,ss,tt;
scanf("%d",&n);S=1;ss=n+1;
ISAP.Init(n+2);T=n;tt=n+2;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d%d",&Min[i][j],&Max[i][j]);
ISAP.addedge(i,j,Max[i][j]-Min[i][j]);
}
}
ISAP.addedge(n,1,INF);
for(int i=1;i<=n;i++){
int ta=0,tb=0;
for(int j=1;j<=n;j++){
ta+=Min[j][i];
tb+=Min[i][j];
}
if(ta>tb)ISAP.addedge(ss,i,ta-tb);
else ISAP.addedge(i,tt,tb-ta);
}ISAP.Max_Flow(ss,tt);
printf("%d\n",ISAP.Max_Flow(S,T));
return 0;
}
如果是求无源汇上下界可行流
不要加最后那条边
对(st,sd)求一次最大流即可,当所有附加边全部满流时(即maxflow==所有du[]>0之和),有可行解。