zoukankan      html  css  js  c++  java
  • 【网络流24】餐巾

    旧题重WA 233

    原题:

     n<=2000

    一眼费用流,简单

    拆点,s到入点流量∞费用p表示直接买,入点到出点r[i]表示每天必须有r[i]条,出点到t流量∞用来保证边被鸽掉,出点再到i+m或i+n的入点表示洗了,入点到下一天的入点流量∞表示洗过的可以屯着

    然后样例就过不了233

    翻以前的博客,发现我三年前第一次做这题的时候就犯了同样的错误233

    我之前的博客认为错误在于如果选择洗,那么这条餐巾的费用为买+洗,大于直接买,所以不会增广

    这个解释不对,费用流就是在保证最大流的情况下费用最小,那么我先买再洗,每条边跑的也是满流,费用更低,为什么费用流得不到方案???

    费用更低是肯定的,费用流也没问题,问题就在于每条边跑满流可不等于最大流

    这个错误主要还是在最大流最小割的概念上不清楚

    把中间的边全鸽了,所用流量确实是最大流

    但是上面的建图如果先买再洗,那么一条流鸽了两条边,总流量不是最大流

    最大流最小割定理只能证明二者在数值上相等

    事实上,如果买+洗方案跑完的残余网络(包括反边)画出来,就可以发现有一条从源到入点,再从入点走反边到出点的流量

    这条反边虽然让费用增加,但也给从源到汇提供了再跑一次的机会

    所以由此可以总结经验,注意最大流一定是从源点到汇点的流量呀

    知道了错误的本质,正解其实不难理解

    为了避免之前的错误,我们要保证每条干净毛巾(不管是买的还是洗的)都必须占用一条从源到汇的完整流量

    需要注意到一个关键性质,每天会稳定地产生r[i]条脏毛巾

    那么我们产销分离,把买的和洗的分开考虑

    因为每天固定会产脏毛巾,所以也不需要再从干净的毛巾里引一条边出来表示洗

    直接把每天拆称脏点和好点,然后从脏点到i+m或i+n天的好点连边,然后源再到脏点流量为r[i],表示每天最多产r[i]条脏毛巾

    源点再到好点连边,表示直接买,好点到汇点流量为r[i],表示每天必须要攒够r[i]条好毛巾

    最后,好点到下一天的好点连边表示屯毛巾就行了

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 #define LL long long
     8 int rd(){int z=0,mk=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mk;
    12 }
    13 const int oo=1000000007;
    14 struct edg{int nxt,y,v,u;}e[31000];  int lk[4100],ltp=1;
    15 void ist(int x,int y,int z,int w){
    16     e[++ltp]=(edg){lk[x],y,z,w};  lk[x]=ltp;
    17     e[++ltp]=(edg){lk[y],x,0,-w};  lk[y]=ltp;
    18 }
    19 int n,m,ft,st,fc,sc,a[2100];
    20 int s,t;
    21 int dstc[4100];
    22 int q[41000],hd=0;  bool vstd[4100];
    23 int lst[4100],lse[4100];
    24 bool spfa(){
    25     for(int i=1;i<=t;++i){
    26         vstd[i]=false;
    27         dstc[i]=oo;
    28     }
    29     dstc[q[hd=1]=s]=0;
    30     for(int k=1;k<=hd;++k){
    31         for(int i=lk[q[k]];i;i=e[i].nxt)
    32             if(e[i].v && dstc[q[k]]+e[i].u<dstc[e[i].y]){
    33                 dstc[e[i].y]=dstc[q[k]]+e[i].u;
    34                 lst[e[i].y]=q[k],lse[e[i].y]=i;
    35                 if(!vstd[e[i].y]){
    36                     q[++hd]=e[i].y;
    37                     vstd[e[i].y]=true;
    38                 }
    39             }
    40         vstd[q[k]]=false;
    41     }
    42     //return dstc[t];  注意不是判断dstc[t]不为0
    43     return dstc[t]!=oo;
    44 }
    45 LL cstflw(){
    46     LL bwl=0;
    47     while(spfa()){
    48         int flw=oo;
    49         for(int i=t;i!=s;i=lst[i])
    50             flw=min(flw,e[lse[i]].v);
    51         for(int i=t;i!=s;i=lst[i]){
    52             bwl+=flw*e[lse[i]].u;
    53             e[lse[i]].v-=flw,e[lse[i]^1].v+=flw;
    54             //cout<<i<<"<-";
    55         }
    56         //cout<<endl;
    57     }
    58     return bwl;
    59 }
    60 int main(){
    61     //freopen("ddd.in","r",stdin);
    62     cin>>n;
    63     for(int i=1;i<=n;++i)  a[i]=rd();
    64     cin>>m>>ft>>fc>>st>>sc;
    65     s=n+n+1,t=n+n+2;
    66     for(int i=1;i<=n;++i){
    67         /*ist(i,i+n,a[i],0);
    68         ist(s,i,oo,m);
    69         ist(i+n,t,oo,0);
    70         if(i<n)  ist(i,i+1,oo,0);
    71         if(i+ft<=n)  ist(i+n,i+ft,oo,fc);
    72         if(i+st<=n)  ist(i+n,i+st,oo,sc);*/
    73         ist(s,i+n,oo,m);
    74         ist(i+n,t,a[i],0);
    75         ist(s,i,a[i],0);
    76         if(i<n)  ist(i,i+1,oo,0);
    77         if(i+ft<=n)  ist(i,i+ft+n,oo,fc);
    78         if(i+st<=n)  ist(i,i+st+n,oo,sc);
    79     }
    80     cout<<cstflw()<<endl;
    81     return 0;
    82 }
    View Code
  • 相关阅读:
    关于MapReduce中自定义分区类(四)
    关于MapReduce中自定义分组类(三)
    UiAutomator2.0
    Java_集合框架
    Python爬取指定重量的快递价格
    Java_面向对象
    Java_异常以及处理
    Java_File类
    Java_Scanner和System类
    Java_Runtime&Process&ProcessBuilder
  • 原文地址:https://www.cnblogs.com/cdcq/p/11872070.html
Copyright © 2011-2022 走看看