zoj3229

题目大意: 一个XX用n天要给m个女神拍写真。这n天里每个女神i分别至少要拍Gi张照片,XX在第j天会给指定Cj个女神最多拍Dj张照片,每个女神第j天拍照数在lj到hj张照片。问XX是否安排完成他的任务,不能输出-1,如果能的话,让他尽可能多拍照。先输出他最多能拍的张数,然后对于输入每一行提到要拍照的女神,按照顺序输出当天那个女神要拍照的张数。(就描述到这了,更多请访问下面的链接)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442

这是一道很典型的有源汇的上下界最大流

容我鸣谢一下先:http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html,我是看了这里报告,自己再搜索资料整理的。

再鸣谢:http://fayaa.com/code/view/26516/是这个帮助我真正理解了的代码(也不是这么说,主要是因为***),虽然这里没有任何语言描述,但博主的代码是SAP实现,容小菜我偷个懒,网络流我都倾向SAP,不习惯dinic,而其他博客一般都是dinic算法写的,读起来太累了。

好吧,还是返回主题了。通常我们求的最大流是上界最大流,而下界都是0。对于无源汇的上下界最大流,大家应该不难理解,把下界边差量du[i](一会儿解释)直接跟我们定义的源点和汇点连起来,自由边(上界边-下界边)按原图留下。现在想想,下界边一定对应一点是入、另一个点是出,若du[i] = in[i]-out[i],那么当du[i]为正时,表明对于点i,一定要流进du[i],我们连边source --> i  with capacity = du[i],否则对于点i一定要流出-du[i],我们连边 i --> sink with capacity = -du[i]。这些就是上下界的全部逻辑翻译了。如果把 sum = sigma(du[i] | du[i] > 0) (或者sum = -sigma(du[i] | du[i] < 0)),那么对构造这个图求一遍最大流,如果maxflow = sum,证明所有限制都能满足了。

当然,有的题目还有一些要求,比如这道题里的:拍照数尽可能多,这就需要后续工作了。当然对于这道题,还有一个特殊的地方,它是有自定义源汇的。那如何把变成无源汇的呢?很简单,假设ss、tt分别是题目定义的源点和汇点,连一条边 tt --> ss with capacity = infinity。这样就形成了环回的一个无源汇的网络图。另外自己再定义超级源点汇点,按照上一段描述得构图判所有限制是否能满足所有限制。

(*)若满足,重设源点、汇点为题目自定义源点、汇点,对于残余网络图求一遍最大流。最后,把网络图里的流入出情况从记录的边中读出来还原出答案就好了。

特别说明一下,有很多博客里都一再强调:对于上一段求最大流时要删掉自定义超级源点、汇点和 ”tt --> ss with capacity = infinity“这条环回边。我是怎么也理解不了了。超级源点只出不入,超级汇点只入不出,它们干那些博主们毛线事???为什么要删掉???环回边的逆向边记录有要满足所有限制必须的流量值。。。删了,你还去哪找更稳妥的这个值????也许我不了解dinic算法,没理解出这些话的强大含义。。。弱弱可以YY一下不,会不会是原始博主写这句话时是他还在学花拳绣腿的时候,而他现在忘了改过来,而千万学习者就未加思索的加上来了呢?反正我是,仅仅更改源点、汇点后,直接对残余网络求最大流AC的。

贴上代码:欢迎大神们提出珍贵建议。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 using namespace std;
  5 const int maxn = 1500;
  6 const int maxe = 1001001;
  7 const int maxf = (-1)^(1<<31);
  8 #define smaller(a,b) ((a)<(b)?(a):(b))
  9 struct edge{
 10        int u,v,c;
 11        edge(int a=0,int b=0,int d=0){ u=a, v=b, c=d; }
 12 }e[maxe];
 13 int head[maxn];
 14 int next[maxe];
 15 int cnt;
 16 void add(int u,int v,int c){
 17      e[cnt] = edge(u,v,c);
 18      next[cnt] = head[u], head[u] = cnt++;
 19      //printf("cnt = %d,	%d --> %d with c = %d, next = %d
",cnt-1,u,v,c,next[cnt-1]);
 20      e[cnt] = edge(v,u,0);
 21      next[cnt] = head[v], head[v] = cnt++;
 22 }
 23 //***********************************//
 24 int source,sink,maxdep;
 25 int dep[maxn],gap[maxn];
 26 int cur[maxn],trace[maxn],que[maxn],top;
 27 void setGD(){
 28      for(int i=0;i<=maxdep;i++) dep[i] = maxdep;
 29      dep[sink] = 0;
 30      int front,rear,u,v;
 31      front = rear = 0;
 32      que[rear++] = sink;
 33      while(front != rear){
 34            u = que[front++];
 35            if(front >= maxn) front = 0;
 36            for(int i=head[u];i!=-1;i=next[i]){
 37                  v = e[i].v;
 38                  //if(v > maxdep) continue;  //这句是删掉超级源点、汇点的句子,删不删都AC。。。
 39                  if(dep[v] < maxdep) continue; //if(e[i].c || dep[v] <= dep[u]+1) continue; //不是逆向边,或者'被访问过'
 40                  dep[v] = dep[u]+1;
 41                  que[rear++] = v;
 42                  if(rear >= maxn) rear = 0;
 43            }
 44      }
 45      memset(gap,0,sizeof(gap));
 46      for(int i=0;i<=maxdep;i++) gap[dep[i]]++;
 47 }
 48 int maxF(){
 49     setGD();
 50     for(int i=0;i<=maxdep;i++) cur[i] = head[i];
 51     int u=source,flow=0,i;
 52     top = 0;
 53     while(dep[source] <= maxdep){
 54         if(u == sink){
 55              int tf = maxf,ins;
 56              for(i=0;i<top;i++){ //找瓶颈边
 57                 if(tf > e[trace[i]].c){
 58                       tf = e[trace[i]].c;
 59                       ins = i;
 60                 }
 61              }
 62 /*
 63              for(i=0;i<top;i++)
 64                 printf("%d -> ",e[trace[i]].u);
 65              printf("%d , temp_flow = %d
",e[trace[top-1]].v,tf);
 66 */
 67              for(i=0;i<top;i++){
 68                 e[trace[i]].c -= tf;
 69                 e[trace[i]^1].c += tf;
 70              }
 71              flow += tf;
 72              u = e[trace[ins]].u, top = ins;
 73         }
 74         if(u != sink && gap[dep[u]-1]==0) break;
 75         for(i=cur[u];i!=-1;i=next[i])
 76              if(e[i].c > 0 && dep[u] == dep[e[i].v] + 1)
 77                        break;
 78         if(i != -1) {
 79              trace[top++] = i;
 80              cur[u] = i;
 81              u = e[i].v;
 82         }
 83         else {
 84              int mindep = maxdep;
 85              for(i=head[u];i!=-1;i=next[i]){
 86                  if(e[i].c && dep[e[i].v] < mindep)
 87                            mindep = dep[e[i].v], cur[u] = i;
 88              }
 89              gap[dep[u]]--;
 90              dep[u] =  mindep + 1;
 91              gap[dep[u]]++;
 92              if(u != source)
 93                 u = e[trace[--top]].u;
 94         }
 95     }
 96     return flow;
 97 }
 98 //**********************************//
 99 int in[maxn],out[maxn],du[maxn],basement;
100 int lownm[370][1010];
101 int order[370][1010],oidx[370];
102 void initial()
103 {
104      cnt = 0;
105      memset(head,-1,sizeof(head));
106      memset(in,0,sizeof(in));
107      memset(out,0,sizeof(out));
108      memset(lownm,0,sizeof(lownm));
109      //initial source ,sink and maxdep;
110 }
111 int main()
112 {
113     int n,m;
114     while(scanf("%d%d",&n,&m) != EOF){
115         initial();
116         source = n+m+8;
117         sink = source+1;
118         maxdep = sink+2;
119         int ss=n+m+1;
120         int tt=ss+1;
121         int fsum = 0;
122         basement = tt;
123         for(int i=0;i<m;i++)
124             scanf("%d",&out[i+n]), in[tt]+=out[i+n], add(i+n,tt,maxf-out[i+n]);
125         int c,d;
126         for(int nn=0;nn<n;nn++){
127             scanf("%d%d",&c,&d);
128             oidx[nn] = c;
129             add(ss,nn,d);
130             int girl,low,up;
131             for(int cc=0;cc<c;cc++){
132                 scanf("%d%d%d",&girl,&low,&up);
133                 lownm[nn][girl]=low;
134                 add(nn,n+girl,up-low);
135                 out[nn]+=low;
136                 in[n+girl] += low;
137                 order[nn][cc] = girl;
138             }
139         }
140         int fcnt = cnt;
141         add(tt,ss,maxf);
142         int sum = 0;
143         for(int i=0;i<=basement;i++){
144             du[i] = in[i]-out[i];
145             if(du[i] > 0) add(source,i,du[i]), sum+=du[i];
146             else if(du[i] < 0) add(i,sink,-du[i]);
147         }
148         int flow = maxF();
149         if(flow < sum) printf("-1

");
150         else {
151             source = ss;
152             sink = tt;
153             maxdep = sink+2;
154             //e[fcnt].c = 0, e[fcnt^1] = 0;
155             flow = maxF();
156             for(int i=0;i<n;i++)
157             for(int j=head[i];j>=0;j=next[j])
158             if(!(j&1))
159                 lownm[i][e[j].v-n] += e[j^1].c;
160             //flow = 0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) flow += lownm[i][j];
161             printf("%d
",flow);
162             for(int i=0;i<n;i++)
163             for(int j=0;j<oidx[i];j++)
164                 printf("%d
",lownm[i][order[i][j]]);
165             puts("");
166         }
167     }
168     return 0;
169 }

另外在贴上一个未AC的代码,这个代码错在构图,***调了我8个小时,还是没搞定。。。

我当时的构图思路是这样的: source --> 某个女神 --> 某一天 --> 汇点。结果就弹了一天。

后来AC代码改成:source  --> 某一天 --> 某个女神--> 汇点。很怀疑是这个special judge的判题程序弱爆了。请有能力的大神给我指点迷津啊。。。

代码如下,请大神斧正!

  1 /*
  2     构图。。。不解,未AC
  3 */
  4 #include <iostream>
  5 #include <cstring>
  6 #include <cstdio>
  7 using namespace std;
  8 const int maxn = 1500;
  9 const int maxe = 1001001;
 10 const int maxf = (-1)^(1<<31);
 11 #define smaller(a,b) ((a)<(b)?(a):(b))
 12 struct edge{
 13        int u,v,c;
 14        edge(int a=0,int b=0,int d=0){ u=a, v=b, c=d; }
 15 }e[maxe];
 16 int head[maxn];
 17 int next[maxe];
 18 int cnt;
 19 void add(int u,int v,int c){
 20      e[cnt] = edge(u,v,c);
 21      next[cnt] = head[u], head[u] = cnt++;
 22      //printf("cnt = %d,	%d --> %d with c = %d, next = %d
",cnt-1,u,v,c,next[cnt-1]);
 23      e[cnt] = edge(v,u,0);
 24      next[cnt] = head[v], head[v] = cnt++;
 25 }
 26 //***********************************//
 27 int source,sink,maxdep;
 28 int dep[maxn],gap[maxn];
 29 int cur[maxn],trace[maxn],que[maxn],top;
 30 void setGD(){
 31      for(int i=0;i<=maxdep;i++) dep[i] = maxdep;
 32      dep[sink] = 0;
 33      int front,rear,u,v;
 34      front = rear = 0;
 35      que[rear++] = sink;
 36      while(front != rear){
 37            u = que[front++];
 38            if(front >= maxn) front = 0;
 39            for(int i=head[u];i!=-1;i=next[i]){
 40                  v = e[i].v;
 41                  if(v > maxdep) continue;
 42                  if(dep[v] < maxdep) continue; //if(e[i].c || dep[v] <= dep[u]+1) continue; //不是逆向边,或者'被访问过'
 43                  dep[v] = dep[u]+1;
 44                  que[rear++] = v;
 45                  if(rear >= maxn) rear = 0;
 46            }
 47      }
 48      memset(gap,0,sizeof(gap));
 49      for(int i=0;i<=maxdep;i++) gap[dep[i]]++;
 50 }
 51 int maxF(){
 52     setGD();
 53     for(int i=0;i<=maxdep;i++) cur[i] = head[i];
 54     int u=source,flow=0,i;
 55     top = 0;
 56     while(dep[source] <= maxdep){
 57         if(u == sink){
 58              int tf = maxf,ins;
 59              for(i=0;i<top;i++){ //找瓶颈边
 60                 if(tf > e[trace[i]].c){
 61                       tf = e[trace[i]].c;
 62                       ins = i;
 63                 }
 64              }
 65 /*
 66              for(i=0;i<top;i++)
 67                 printf("%d -> ",e[trace[i]].u);
 68              printf("%d , temp_flow = %d
",e[trace[top-1]].v,tf);
 69 */
 70              for(i=0;i<top;i++){
 71                 e[trace[i]].c -= tf;
 72                 e[trace[i]^1].c += tf;
 73              }
 74              flow += tf;
 75              u = e[trace[ins]].u, top = ins;
 76         }
 77         if(u != sink && gap[dep[u]-1]==0) break;
 78         for(i=cur[u];i!=-1;i=next[i])
 79              if(e[i].c > 0 && dep[u] == dep[e[i].v] + 1)
 80                        break;
 81         if(i != -1) {
 82              trace[top++] = i;
 83              cur[u] = i;
 84              u = e[i].v;
 85         }
 86         else {
 87              int mindep = maxdep;
 88              for(i=head[u];i!=-1;i=next[i]){
 89                  if(e[i].c && dep[e[i].v] < mindep)
 90                            mindep = dep[e[i].v], cur[u] = i;
 91              }
 92              gap[dep[u]]--;
 93              dep[u] =  mindep + 1;
 94              gap[dep[u]]++;
 95              if(u != source)
 96                 u = e[trace[--top]].u;
 97         }
 98     }
 99     return flow;
100 }
101 //**********************************//
102 int in[maxn],out[maxn],du[maxn],basement;
103 int lownm[370][1010];
104 int order[370][1010],oidx[370];
105 void initial()
106 {
107      cnt = 0;
108      memset(head,-1,sizeof(head));
109      memset(in,0,sizeof(in));
110      memset(out,0,sizeof(out));
111      memset(lownm,0,sizeof(lownm));
112      //initial source ,sink and maxdep;
113 }
114 int main()
115 {
116     int n,m;
117     while(scanf("%d%d",&n,&m) != EOF){
118         initial();
119         source = n+m+8;
120         sink = source+1;
121         maxdep = sink+2;
122         int ss=n+m+1;
123         int tt=ss+1;
124         int fsum = 0;
125         basement = tt;
126         for(int i=0;i<m;i++)
127             scanf("%d",&in[i]), out[ss]+=in[i], add(ss,i,maxf), fsum+=in[i];
128         int c,d;
129         for(int nn=0;nn<n;nn++){
130             scanf("%d%d",&c,&d);
131             oidx[nn] = c;
132             int girl,low,up;
133             for(int cc=0;cc<c;cc++){
134                 scanf("%d%d%d",&girl,&low,&up);
135                 lownm[nn][girl]=low;
136                 add(girl,m+nn,up-low);
137                 out[girl]+=low;
138                 in[m+nn] +=low;
139                 order[nn][cc] = girl;
140             }
141             add(m+nn,tt,d);
142         }
143         int fcnt = cnt;
144         add(tt,ss,maxf);
145         int sum = 0;
146         for(int i=0;i<=basement;i++){
147             du[i] = in[i]-out[i];
148             if(du[i] > 0) add(source,i,du[i]), sum+=du[i];
149             else if(du[i] < 0) add(i,sink,-du[i]);
150         }
151         int flow = maxF();
152         int flag = 1;
153         for(int i=head[source];i>=0;i=next[i])
154         if(e[i].c){
155             flag = 0;
156             break;
157         }
158         if(!flag) printf("-1

");
159         else {
160             source = ss;
161             sink = tt;
162             maxdep = sink+2;
163             //e[fcnt].c = 0, e[fcnt^1] = 0;
164             flow = maxF();
165             for(int i=n+m;i>=m;i--)
166             for(int j=head[i];j>=0;j=next[j])
167             if(j&1)
168                 lownm[i-m][e[j].v] += e[j].c;
169             //flow = 0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) flow += lownm[i][j];
170             printf("%d
",flow);
171             for(int i=0;i<n;i++)
172             for(int j=0;j<oidx[i];j++)
173                 printf("%d
",lownm[i][order[i][j]]);
174             puts("");
175         }
176     }
177     return 0;
178 }
原文地址:https://www.cnblogs.com/karlvin/p/3239409.html