zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    如何选择硅谷的IT公司
    NSDateFormatter设定日期格式
    内存映射文件
    double 转 int 的精度损失问题
    #ifndef #define 的用法
    How to improve the performance of MB5B
    Vendor Evaluation Questionair弹出空白页
    接受报价后创建合同,却无法弹出相应的合同类型
    SRM税务代码的决定逻辑
    How to improve the performance of MB51
  • 原文地址:https://www.cnblogs.com/karlvin/p/3239409.html
Copyright © 2011-2022 走看看