loj115 无源汇有上下界可行流
loj115
1 题目描述
这是一道模板题。
n个点, m条边,每条边 有一个流量下界\(low(e)\)和流量上界\(up(e)\) ,求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。
2 分析
首先: 我们先把下界的流量放到每条边上去,这样我们就可以算出每个点进入的流量\(in[x]\),流出的流量\(out[x]\)。这条边的剩余容量为\(up-low\)。
我们新增一个源点s和汇点t,如果某个点x,\(in[x]>out[x]\),即流入大于流出,我们可以在s到x建一条容量为\(in[x]-out[x]\)的边,反之,如果\(in[x]<out[x]\),我们就在x到t建立一条容量为\(out[x]-in[x]\)的边。
最后我们判断从s到t的最大流是否等于s到其他点的容量总和,如果可以达到,就表明这个可行流是存在的。
3 代码
#include<bits/stdc++.h>
using namespace std;
int const N=200+5;
int const M=40000;
int const inf=1e9;
struct edge{
int to,nt,capa,fl,id;
}e[M];
int n,m,h[N],cnt,d[N],q[N],low[M],up[M],s,t,work[N],in[N],out[N],res[M];
void add(int a,int b,int capa,int id){
e[cnt].to=b;
e[cnt].nt=h[a];
e[cnt].capa=capa;
e[cnt].fl=0;
e[cnt].id=id;
h[a]=cnt++;
}
int bfs(){
memset(d,-1,sizeof(d));
int cl=1; q[0]=s; d[s]=0;
for(int i=0;i<cl;i++){
int x=q[i];
for(int j=h[x];j!=-1;j=e[j].nt)
if(e[j].capa>e[j].fl && d[e[j].to]==-1){
d[e[j].to]=d[x]+1;
q[cl++]=e[j].to;
}
}
return d[t]>-1;
}
int dfs(int x,int flow){
if(x==t) return flow;
for(int &i=work[x];i!=-1;i=e[i].nt){
int v=e[i].to,tmp=0;
if(e[i].capa>e[i].fl && d[v]==d[x]+1 && (tmp=dfs(v,min(flow,e[i].capa-e[i].fl)))){
e[i].fl+=tmp;
e[i^1].fl-=tmp;
return tmp;
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
s=0,t=n+1;
memset(h,-1,sizeof(h));
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d%d%d",&x,&y,&low[i],&up[i]);
out[x]+=low[i];
in[y]+=low[i];
add(x,y,up[i]-low[i],i);
add(y,x,0,-i);
}
int sum=0;
for(int i=1;i<=n;i++)
if(in[i]<out[i]) {
add(i,t,out[i]-in[i],0);
add(t,i,0,0);
}else if(in[i]>out[i]){
add(s,i,in[i]-out[i],0);
sum+=in[i]-out[i];
add(i,s,0,0);
}
int ans=0;
while (bfs()){
memcpy(work,h,sizeof(h));
int tmp;
while ((tmp=dfs(s,inf))) ans+=tmp;
}
if(ans!=sum) printf("NO\n");
else {
printf("YES\n");
for(int i=1;i<=n;i++){
for(int j=h[i];j!=-1;j=e[j].nt){
if(e[j].id>0){
res[e[j].id]+=e[j].fl;
}
}
}
for(int i=1;i<=m;i++)
cout<<low[i]+res[i]<<endl;
}
return 0;
}