zoukankan      html  css  js  c++  java
  • 【BZOJ 2879】[Noi2012]美食节 费用流

    思路同修车,就是多了一个骚气的操作:动态加边,我们通过spfa流的过程可以知道,我们一次只会跑一流量,最后一层边跑过就不会再悔改,所以说我们只会用到一大片里面的很少的点,所以我们如果可以动态加边的话我们的边的数量就会从n*m*p级别减少到p*n级别,点数的话有些点虽然存在但是由于我们没连上所以就不会有任何用。
    这道题告诉我网络流的图并不是静态的他也是可以动态的变化,这道题只是动态得加一些边,还会有什么呢?这道题的动态加边只是为了提高时间效率,还有其他的作用吗?

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=45;
    const int M=105;
    const int P=805;
    const int O=P*M;
    const int E=P*M*N*2;
    const int Inf=0x3f3f3f3f;
    struct V{
      int to,next,c,f;
    }c[E];
    int head[O],t=1;
    inline void add(int x,int y,int z,int _){
      c[++t].to=y,c[t].next=head[x],c[t].f=z,c[t].c=_,head[x]=t;
    }
    int dis[O],anc[O],p[N];
    int q[O],front,back;
    bool in[O];
    int n,m,sum;
    int S,T,ans;
    bool link[M][P];
    int val[N][M];
    #define food(a) (a)
    #define cook(a,b) (((a)-1)*sum+(b)+n)
    inline bool spfa(){
      memset(dis,0x3f,sizeof(dis));
      dis[S]=0,in[S]=true,q[back++]=S;
      if(back==O)back=0;
      while(front!=back){
        int x=q[front++];in[x]=false;
        if(front==O)front=0;
        for(int i=head[x];i;i=c[i].next)
          if(c[i].f&&dis[x]+c[i].c<dis[c[i].to]){
            dis[c[i].to]=dis[x]+c[i].c,anc[c[i].to]=i;
            if(!in[c[i].to]){
              q[back++]=c[i].to,in[c[i].to]=true;
              if(back==O)back=0;
            }
          }
      }
      return dis[T]!=Inf;
    }
    inline int shoot(){
      int f=Inf;
      for(int i=anc[T];i;i=anc[c[i^1].to])f=std::min(f,c[i].f);
      for(int i=anc[T];i;i=anc[c[i^1].to])c[i].f-=f,c[i^1].f+=f;
      int key=c[anc[T]^1].to-n;
      int y=key%sum==0?sum:key%sum;
      int x=(key-y)/sum+1;
      if(y!=sum&&link[x][y+1]==false){
        link[x][y+1]=true;
        for(int i=1;i<=n;++i){
          add(food(i),cook(x,y+1),1,(y+1)*val[i][x]);
          add(cook(x,y+1),food(i),0,-(y+1)*val[i][x]);
        }
        add(cook(x,y+1),T,1,0);
        add(T,cook(x,y+1),0,0);
      }
      return f*dis[T];
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;++i)
        scanf("%d",&p[i]),sum+=p[i];
      S=sum*m+n+1,T=S+1;
      for(int i=1;i<=n;++i){
        add(S,food(i),p[i],0);
        add(food(i),S,0,0);
      }
      for(int i=1;i<=m;++i){
          add(cook(i,1),T,1,0);
          add(T,cook(i,1),0,0);
          link[i][1]=true;
        }
      for(int i=1,x;i<=n;++i)
        for(int j=1;j<=m;++j){
          scanf("%d",&x);
          add(food(i),cook(j,1),1,x);
          add(cook(j,1),food(i),0,-x);
          val[i][j]=x;
        }
      while(spfa())ans+=shoot();
      printf("%d",ans);
      return 0;
    }
  • 相关阅读:
    webbrowser在vb中叫
    linux小记之安装bin或deb程序
    9011,9012,9013,9014,8050,8550三极管的区别
    中兴v880刷机全过程。原创亲测
    Slackware的启动(init)过程
    sysvinit
    rc.S 分析【转自CSDN 】
    linux 解压rar zip
    slackware启动脚本详解
    工作
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8010520.html
Copyright © 2011-2022 走看看