无源汇上下界网络流 zju zoj 2314

类型:无源汇可行流

参考自()

http://hi.baidu.com/evelynhe/blog/item/f1c5ba2fcbe674271e3089ad.html

每条边的容量满足一定的限制,即有一个上限值,也有一个下限值

上界用ci表示,下界用bi表示。

下界是必须流满的,那么对于每一条边,去掉下界后,其自由流为ci– bi。

主要思想:每一个点流进来的流=流出去的流

对于每一个点i,令

Mi= sum(i点所有流进来的下界流)– sum(i点所有流出去的下界流)

如果Mi大于0,代表此点必须还要流出去Mi的自由流,那么我们从源点连一条Mi的边到该点。

如果Mi小于0,代表此点必须还要流进来Mi的自由流,那么我们从该点连一条Mi的边到汇点。

如果求S->T的最大流,看是否满流(S的相邻边都流满)。

满流则有解,否则无解。

View Code
#include<stdio.h>
#include<string.h>
const int MAX=100005;
const int INF=1000000000;
struct EDGE
{
int v,c,next;
}edge[1000000];
int E,head[MAX];
int gap[MAX],cur[MAX];
int pre[MAX],dis[MAX];
int in[225],low[50000];
void add_edge(int s,int t,int c,int cc)
{
edge[E].v=t; edge[E].c=c;
edge[E].next=head[s];
head[s]=E++;
edge[E].v=s; edge[E].c=cc;
edge[E].next=head[t];
head[t]=E++;
}
int min(int a,int b){return (a==-1||b<a)?b:a;}
int SAP(int s,int t,int n)
{
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
int i;
for(i=0;i<n;i++)cur[i]=head[i];
int u=pre[s]=s,maxflow=0,aug=-1,v;
gap[0]=n;
while(dis[s]<n)
{
loop: for(i=cur[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[u]==dis[v]+1)
{
aug=min(aug,edge[i].c);
pre[v]=u;
cur[u]=i;
u=v;
if(u==t)
{
for(u=pre[u];v!=s;v=u,u=pre[u])
{
edge[cur[u]].c-=aug;
edge[cur[u]^1].c+=aug;
}
maxflow+=aug;
aug=-1;
}
goto loop;
}
}
int mindis=n;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[v]<mindis)
{
cur[u]=i;
mindis=dis[v];
}
}
if((--gap[dis[u]])==0)break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return maxflow;
}
bool solve(int n)
{
for(int i=1;i<=n;i++)
{
if(in[i]>0) add_edge(0,i,in[i],0);
if(in[i]<0) add_edge(i,n+1,-in[i],0);
}
SAP(0,n+1,n+2);
for(int i=head[0];i!=-1;i=edge[i].next)//从源点出发的边都满流
{
if(edge[i].c) return false;
}
return true;
}
int main()
{
int t,n,m,a,b,c;
scanf("%d",&t);
while(t--)
{
E=0;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&a,&b,&low[i],&c);
in[a]-=low[i],in[b]+=low[i];
add_edge(a,b,c-low[i],0);
}
if(solve(n))
{
printf("YES\n");
for(int i=0;i<m;i++)
printf("%d\n",edge[(i<<1)^1].c+low[i]);//反向的流即自由流,再加上下界的流
}
else printf("NO\n");
puts("");
}
return 0;
}



posted @ 2012-02-29 16:24  Because Of You  Views(1021)  Comments(0Edit  收藏  举报