zoj 3229 Shoot the Bullet--有源汇 有上下界 最大流 递归和非递归sap

来源:互联网 发布:单片机学习网站 编辑:程序博客网 时间:2024/05/16 16:57
/*题目大意:某人n天给m个美女拍照每个美女都有一个最低要求每天有一个照片数量上限先给出n m每个美女的下限n个{ 第i天拍照的美女数  这天的照片数量上限依次是  美女编号  这天的下限  上限}有源汇 有上下界 最大流先对 附加 源汇ss tt求依次最大流若有可行流 再对s t求最大流这是第二次写这个题,第一次写的挺不顺利(可能是构图的时候出问题了,不是超时就是错,求最大流的方法就换了三种:sap递归,sap非递归,dinic我都怀疑我的最大流模版是不是有漏洞,下面的递归sap就是最初用的,当时我还以为这个有问题,其实,还真有一个问题,下面有,但是该了还是超时,今天看来,是构图的问题)下面的  非递归sap跑了330ms   递归sap跑了270ms  看来我的模版速度还是不错的*/#include<stdio.h>#include<string.h>#define inf 0x7fffffffstruct edge//边{int u,v,f,next,b,c;//边的 前节点 后节点 可用流 下条边的编号  原来边上流的上下界}e[400000];int head[1400],in[1400],out[1400],n,m,s,t,ss,tt,yong,indexx[400000],ind,sum;/*head 链表头  in  某点的 流入下界和 - 流出下界和  out没用到yong 指向下一个未用的边  indexx 存储某个美女某天的边的编号index在string.h里边有所以改成这个了  ind 表示下一个未用的 indexxsum  流入tt的流量和  判断有无可行解用*/void ini()//初始化{memset(head,-1,sizeof(head));yong=0;memset(in,0,sizeof(in));s=m+n,t=s+1,ss=t+1,tt=ss+1;ind=0;sum=0;}void adde(int from,int to,int xia,int shang)//加边{//加边e[yong].u=from,e[yong].v=to,e[yong].f=shang-xia,e[yong].b=xia,e[yong].c=shang;e[yong].next=head[from],head[from]=yong++;//同时加它的退边e[yong].u=to,e[yong].v=from,e[yong].f=0,e[yong].b=xia,e[yong].c=shang;e[yong].next=head[to],head[to]=yong++;}void build()//构造必要弧//http://blog.csdn.net/qq172108805/article/details/7783010上有关于这个的简要说明{int i;for(i=0;i<=t;++i){if(in[i]>0)adde(ss,i,0,in[i]);else{adde(i,tt,0,-in[i]);sum+=(-in[i]);}}}int sap(int s,int t)//非递归sap{int i,j,ff=0,v,cur[1400],d[1400],num[1400],low[1400],pre[1400];memset(low,0,sizeof(low));memset(d,0,sizeof(d));memset(num,0,sizeof(num));for(i=0;i<=t;++i)cur[i]=head[i];low[i=s]=inf;num[s]=t+1;while(d[s]<t+1){for(j=cur[i];j!=-1;j=e[j].next)if(e[j].f>0&&d[i]==d[v=e[j].v]+1)break;cur[i]=j;if(j>=0){pre[v]=j;low[v]=e[j].f;if(low[v]>low[i])low[v]=low[i];i=v;if(i==t){for(;i!=s;i=e[pre[i]].u){e[pre[i]].f-=low[t];e[pre[i]^1].f+=low[t];}ff+=low[t];memset(low,0,sizeof(low));low[s]=inf;}}else{if(--num[d[i]]==0)break;d[i]=t+1;cur[i]=head[i];for(j=head[i];j!=-1;j=e[j].next)if(e[j].f>0&&d[i]>d[e[j].v]+1)d[i]=d[e[j].v]+1;num[d[i]]++;if(i!=s)i=e[pre[i]].u;}}return ff;}int d[1400],num[1400];int min(int a,int b){return a<b?a:b;}int sap_gap(int u,int f,int s,int t)//递归sap{if(u==t)return f;int i,v,mind=t,last=f,cost;for(i=head[u];i!=-1;i=e[i].next){v=e[i].v;int flow=e[i].f;if(flow>0)//参考模版写的时候把flow写成了f{if(d[u]==d[v]+1){cost=sap_gap(v,min(last,flow),s,t);e[i].f-=cost;e[i^1].f+=cost;last-=cost;if(d[s]>=t+1)return f-last;if(last==0)break;}if(d[v]<mind)mind=d[v];}}if(last==f){--num[d[u]];if(num[d[u]]==0)d[s]=t+1;d[u]=mind+1;++num[d[u]];}return f-last;}int max_f(int s,int t)//调用递归sap{int f=0;memset(d,0,sizeof(d));memset(num,0,sizeof(num));for(num[s]=t+1;d[s]<t+1;)f+=sap_gap(s,inf,s,t);return f;}int main(){int i,a,c,b,ng,most,sun;while(scanf("%d%d",&n,&m)!=EOF){ini();for(i=0;i<m;i++){scanf("%d",&a);adde(i,t,a,inf);in[t]+=a;in[i]-=a;}for(;i<m+n;++i){scanf("%d%d",&ng,&most);adde(s,i,0,most);while(ng--){scanf("%d%d%d",&a,&b,&c);indexx[ind++]=yong;adde(i,a,b,c);in[a]+=b;in[i]-=b;}}adde(t,s,0,inf);build();//sun=sap(s,tt);//非递归sapsun=max_f(ss,tt);//递归sapif(sun!=sum){printf("-1\n");}else{//sap(s,t);//非递归sapmax_f(s,t);//递归sapb=0;for(i=0;i<ind;++i){a=indexx[i];b+=e[a].c-e[a].f;}printf("%d\n",b);for(i=0;i<ind;++i){a=indexx[i];printf("%d\n",e[a].c-e[a].f);}}printf("\n");}return 0;}

原创粉丝点击