您的位置:首页 > 其它

ZOJ 3229 有上下界最大流

2014-05-08 17:55 204 查看
/**
ZOJ3229有上下界的最大流
两次求最大流的过程,非二分
有源汇上下界的最大流问题,首先连接sink->src,[0,INF].
根据net的正负,来建立Supersrc与supersink之间的边,做一次maxflow.
若所有的Supersrc与Supersink满流,则说明存在可行流.
然后删除sink->src之间的边.(cap置零即可).从src->sink做一次最大流.
两次最大流的和即为整个网络的最大流.
*/
#include<iostream>
#include<cmath>
#include<memory>
#include<string.h>
#include<cstdio>
#include<vector>
usingnamespacestd;
#defineV1500//vertex
#defineEV*80//edge
#defineINF0x3F3F3F3F//1061109567
inti,j,k;
#defineREP(i,n)for((i)=0;(i)<(int)(n);(i)++)
#definesnuke(c,itr)for(__typeof((c).begin())itr=(c).begin();itr!=(c).end();itr++)
structMaxFlow
{
structEdge
{
intv,w,next;//wforcapicity
intlb,up;
}edge[E];
inthead[V];//head[u]表示顶点u第一条邻接边的序号,若head[u]=-1,u没有邻接边
inte;//theindexoftheedge
intsrc,sink;
intnet[V];//流入此节点的流的下界和-流出此节点的流的下界和,对于带上下界的来进行使用
voidaddedge(intu,intv,intw,intlb=0,intup=INF,intrw=0)
{
edge[e].v=v;
edge[e].w=w;
edge[e].next=head[u];
edge[e].lb=lb,edge[e].up=up;
head[u]=e++;
//reverseedgev->u
edge[e].v=u;
edge[e].w=rw;
edge[e].lb=lb,edge[e].up=up;
edge[e].next=head[v];
head[v]=e++;
}
intISAP(intVertexNum)
{
intu,v,max_flow,aug,min_lev;
intcuredge[V],parent[V],level[V];
intcount[V],augment[V];
memset(level,0,sizeof(level));
memset(count,0,sizeof(count));
REP(i,VertexNum+1)curedge[i]=head[i];
max_flow=0;
augment[src]=INF;
parent[src]=-1;
u=src;
while(level[src]<VertexNum)
{
if(u==sink)
{
max_flow+=augment[sink];
aug=augment[sink];
for(v=parent[sink];v!=-1;v=parent[v])
{
i=curedge[v];
edge[i].w-=aug;
edge[i^1].w+=aug;
augment[edge[i].v]-=aug;
if(edge[i].w==0)u=v;
}
}
for(i=curedge[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].w>0&&level[u]==(level[v]+1))
{
augment[v]=min(augment[u],edge[i].w);
curedge[u]=i;
parent[v]=u;
u=v;
break;
}
}
if(i==-1)
{
if(--count[level[u]]==0)break;
curedge[u]=head[u];
min_lev=VertexNum;
for(i=head[u];i!=-1;i=edge[i].next)
if(edge[i].w>0)
min_lev=min(level[edge[i].v],min_lev);
level[u]=min_lev+1;
count[level[u]]++;
if(u!=src)u=parent[u];
}
}
returnmax_flow;
}
//girl0-m-1,daym,m+n-1,srcm+n,sinkm+n+1.allm+n+2point
voidsolve()
{
intN,M;//ndaysmgirl
while(scanf("%d%d",&N,&M)!=EOF)
{
e=0;
memset(head,-1,sizeof(head));
memset(net,0,sizeof(net));
intG;src=M+N,sink=M+N+1;
for(inti=0;i<M;i++)
{
scanf("%d",&G);
addedge(i,sink,INF-G,G,INF);
net[i]-=G;
net[sink]+=G;
}
vector<int>CE;
for(inti=0;i<N;i++)
{
intC,D;scanf("%d%d",&C,&D);
addedge(src,M+i,D,0,D);
for(intj=0;j<C;j++)
{
intT,L,R;scanf("%d%d%d",&T,&L,&R);
CE.push_back(e);
addedge(M+i,T,R-L,L,R);
net[M+i]-=L;
net[T]+=L;
}
}
intspec=e;
//添加从sink->src容量为INF的边
addedge(sink,src,INF,0,INF);
src=M+N+2;sink=M+N+3;//M+N+4point
intrangea=e;
for(inti=0;i<M+N+2;i++)
{
if(net[i]>=0)addedge(src,i,net[i]);
elseaddedge(i,sink,-net[i]);
}
doubleret=0;
intrangeb=e;
//从supersrc->supersink做一次最大流
ret+=ISAP(M+N+4);
boolflag=true;
//判断是否满流
for(inti=rangea;i<rangeb;i+=2)
{
if(edge[i].w!=0)
{
flag=false;
break;
}
}
if(flag)
{
//修改srcsink,然后把从sink->src的边删除
src=M+N;sink=M+N+1;
edge[spec].w=0;edge[spec+1].w=0;
//从src->sink做一次最大流
ret+=ISAP(M+N+2);
inttmp=ret;
printf("%d\n",tmp);
for(inti=0;i<CE.size();i++)
printf("%d\n",edge[CE[i]+1].lb+edge[CE[i]+1].w);
}elseprintf("-1\n");
cout<<endl;
}
}
}sap;
intmain()
{
//freopen("1.txt","r",stdin);
sap.solve();
return0;
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: