网络流ZOJ 3229 Shoot the Bullet
Posted Coolxxx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流ZOJ 3229 Shoot the Bullet相关的知识,希望对你有一定的参考价值。
题目链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3229
题目大意:
n天给m个女孩拍照(1<=n<=365,1<=m<=1000),每个女孩X在n天里总共至少拍Gx张照片。
第k天可以给Ck个女孩拍照,当天总共最多拍Dk张照片,每个女孩这天被拍的数量在[Li,Ri]。
满足要求的条件下尽量多拍照。
求是否有可行解,没有输出-1,有的话输出最大流以及每天对该天能拍照的女孩的拍照数量(巨坑。。怪我没读清题意。wa了好久)。
数据输入:
最多40组数据,多组数据,第一行两个数n和m,第二行m个数Gx。
接下来输入n天的信息,第一行为每天的Ck,Dk,接下来C行输入今天可以拍的女孩编号T(从0开始),L,R。
题目思路:
【有源汇上下界最大流】
设源s和汇t,s向第i天连(0,Di)的边,第i天向当天的Ck个女孩连(Li,Ri)的边,最后每个女孩向t连(Gi,∞)的边。
这样这题就转化成有上下界的最大流了。
接下来设超级源S和超级汇T,将有上下界的图转成无上下界的图。
从S到T跑一边最大流,如果每条S的出边都满流则有解,否则无解。
有解的情况下把S和T删掉(听说不删也可以?),从s到t跑一边最大流,即为答案(别忘了加上下界)。
建图方法:
设每条边上界为c,下界为b,将每条边的上界改为c-b。
我们开设一个数组in[]来记录每个节点的流量情况。
in[i]=Σi入下界-Σi出下界(i节点所有入流下界之和-i节点所有出流下界之和)。
当in[i]大于0的时候,S到i连一条流量为in[i]的边。
当in[i]小于0的时候,i到T连一条流量为-in[i]的边。
最后对(S,T)求一次最大流即可,当所有附加边全部满流时(S的出边都满流时),有可行解。
1 // 2 //by coolxxx 3 // 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #include<iomanip> 8 #include<memory.h> 9 #include<time.h> 10 #include<stdio.h> 11 #include<stdlib.h> 12 #include<string.h> 13 #include<stdbool.h> 14 #include<math.h> 15 #define min(a,b) ((a)<(b)?(a):(b)) 16 #define max(a,b) ((a)>(b)?(a):(b)) 17 #define abs(a) ((a)>0?(a):(-(a))) 18 #define lowbit(a) (a&(-a)) 19 #define sqr(a) (a)*(a) 20 #define swap(a,b) (a)^=(b),(b)^=(a),(a)^=(b) 21 #define eps 1e-8 22 #define MAX 0x7f7f7f7f 23 #define INF 20000 24 #define PI 3.1415926535897 25 #define N 2004 26 #define M 2000004 27 using namespace std; 28 int n,m,cas,lll,ans; 29 int S,T,nn,s,t; 30 int last[N],in[N],d[N],vd[N],day[400]; 31 int low[M]; 32 struct xxx 33 { 34 int next,to,f; 35 }e[M]; 36 void add(int x,int y,int f) 37 { 38 e[++lll].next=last[x]; 39 last[x]=lll; 40 e[lll].to=y; 41 e[lll].f=f; 42 } 43 void link(int x,int y,int f) 44 { 45 add(x,y,f); 46 add(y,x,0); 47 } 48 void build() 49 { 50 int i,j,f,x,y,b,c; 51 lll=1;ans=0; 52 scanf("%d",&m); 53 s=n+m+1;t=n+m+2; 54 for(i=1;i<=m;i++) 55 { 56 scanf("%d",&x);//Gx 57 //link(n+i,t,MAX-x); 58 in[n+i]-=x;in[t]+=x; 59 } 60 for(i=1;i<=n;i++) 61 { 62 scanf("%d%d",&x,&day[i]);//C D 63 //link(s,i,f); 64 for(j=1;j<=x;j++) 65 { 66 scanf("%d%d%d",&y,&b,&c); 67 y++; 68 link(i,n+y,c-b); 69 in[i]-=b;in[n+y]+=b; 70 low[++low[0]]=b; 71 } 72 } 73 S=t+1; 74 T=t+2; 75 nn=n+m+4; 76 for(i=1;i<=n+m+2;i++) 77 { 78 if(in[i]>0)link(S,i,in[i]); 79 if(in[i]<0)link(i,T,-in[i]); 80 } 81 for(i=1;i<=m;i++)link(n+i,t,MAX); 82 for(i=1;i<=n;i++)link(s,i,day[i]); 83 link(t,s,MAX); 84 } 85 int sap(int u,int f,int T) 86 { 87 int i,tt,asp=0,mix=nn-1; 88 if(u==T)return f; 89 for(i=last[u];i;i=e[i].next) 90 { 91 if(e[i].f>0) 92 { 93 if(d[u]==d[e[i].to]+1) 94 { 95 tt=sap(e[i].to,min(f-asp,e[i].f),T); 96 asp+=tt; 97 e[i].f-=tt; 98 e[i^1].f+=tt; 99 if(asp==f || d[S]==nn) 100 return asp; 101 } 102 mix=min(mix,d[e[i].to]); 103 } 104 } 105 if(asp!=0)return asp; 106 if(!--vd[d[u]])d[S]=nn; 107 else vd[d[u]=mix+1]++; 108 return asp; 109 } 110 void maxflow(int S,int T) 111 { 112 int f; 113 memset(d,0,sizeof(d)); 114 memset(vd,0,sizeof(vd)); 115 vd[0]=nn; 116 while(d[S]<nn) 117 { 118 f=sap(S,MAX,T); 119 ans+=f; 120 } 121 } 122 int main() 123 { 124 #ifndef ONLINE_JUDGE 125 // freopen("1.txt","r",stdin); 126 // freopen("2.txt","w",stdout); 127 #endif 128 int i,j,f; 129 // while(~scanf("%s",s)) 130 while(~scanf("%d",&n) && n) 131 { 132 build(); 133 maxflow(S,T); 134 for(i=last[S],f=1;i;i=e[i].next) 135 { 136 if(e[i].f>0) 137 { 138 f=0; 139 break; 140 } 141 } 142 if(!f) 143 puts("-1"); 144 else 145 { 146 last[S]=last[T]=0; 147 ans=0; 148 maxflow(s,t); 149 printf("%d\n",ans); 150 for(i=1;i<=low[0];i++) 151 printf("%d\n",low[i]+e[(i<<1)^1].f); 152 } 153 low[0]=0; 154 memset(in,0,sizeof(in)); 155 memset(last,0,sizeof(last)); 156 puts(""); 157 } 158 return 0; 159 } 160 161 162 /* 163 // 164 165 // 166 */
以上是关于网络流ZOJ 3229 Shoot the Bullet的主要内容,如果未能解决你的问题,请参考以下文章
zoj 3229 Shoot the Bullet(有源汇上下界最大流)
ZOJ 3229 Shoot the Bullet (有源有汇有上下界最大流)