zoukankan      html  css  js  c++  java
  • [ ZJOI 2010 ] 网络扩容

    (\)

    Description


    给定一张有向图,每条边都有一个容量 (C) 和一个扩容费用 (W)

    这里扩容费用是指将容量扩大 (1) 所需的费用。求:

    • 在不扩容的情况下, (1)(N) 的最大流;

    • (1)(N) 的最大流增加 (K) 所需的最小扩容费用。

    • (nle 10^3,mle 5 imes 10^3,Kle 10)

    (\)

    Solution


    注意残量网络的作用。

    第一问直接最大流就好了。

    主要是第二问。难道答案就是重建图求 (K) 股流的最小费用吗?

    并不是,因为第一次跑完最大流剩下的残量网络里的边还可以接着用,并不需要花费代价扩容。

    所以要在原图的基础上重建图,新编费用对应,流量上限为 (infty)

    跑一遍 (K) 股流的最小费用就可以了。

    (\)

    Code


    实现的时候其实可以直接跑费用流。

    一开始的边费用为 (0) ,新加的边有费用即可。

    注意 (K) 股流的时候需要讨论一下,否则增广路是无穷的。

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 1010
    #define M 20010
    #define R register
    #define gc getchar
    #define inf 1000000000
    using namespace std;
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int n,m,tot=1,hd[N];
    
    struct edge{int f,w,to,nxt;}e[M];
    
    inline void add(int u,int v,int w,int f){
      e[++tot].to=v; e[tot].nxt=hd[u];
      e[tot].f=f; e[tot].w=w; hd[u]=tot;
    }
    
    struct E{int u,v,w,f;}r[M];
    
    int vis[N];
    
    int s,t,k,id[N],pre[N],dis[N];
    
    queue<int> q;
    
    inline bool spfa(){
      for(R int i=1;i<=n;++i) dis[i]=inf,vis[i]=0;
      dis[s]=0; q.push(s);
      while(!q.empty()){
        int u=q.front();
        q.pop(); vis[u]=0;
        for(R int i=hd[u],v;i;i=e[i].nxt)
          if(e[i].f&&(dis[v=e[i].to]>dis[u]+e[i].w)){
            dis[v]=dis[u]+e[i].w;
            pre[v]=u; id[v]=i;
            if(!vis[v]) vis[v]=1,q.push(v);
          }
      }
      return dis[t]<inf;
    }
    
    inline pair<int,int> mcmf(int lim){
      int res=0,totf=0,tmp;
      while(spfa()){
        tmp=inf;
        for(R int i=t;i!=s;i=pre[i]) tmp=min(tmp,e[id[i]].f);
        for(R int i=t;i!=s;i=pre[i]){
          e[id[i]].f-=tmp; e[id[i]^1].f+=tmp;
        }
        totf+=tmp;
        if(totf>=lim){
          res+=(tmp-(totf-lim))*dis[t];
          break;
        }
        else res+=tmp*dis[t];
      }
      return make_pair(totf,res);
    }
    
    int main(){
      n=rd(); m=rd();
      k=rd(); s=1; t=n;
      for(R int i=1,u,v,f,w;i<=m;++i){
        u=rd(); v=rd(); f=rd(); w=rd();
        r[i]=(E){u,v,w,f};
        add(u,v,0,f); add(v,u,0,0);
      }
      printf("%d ",mcmf(inf).first);
      for(R int i=1,u,v,w;i<=m;++i){
        u=r[i].u; v=r[i].v; w=r[i].w;
        add(u,v,w,inf); add(v,u,-w,0);
      }
      printf("%d
    ",mcmf(k).second);
      return 0;
    }
    
  • 相关阅读:
    yii2.0 干货
    VLD opcodes 在线查看
    定长顺序串的实现
    循环队列
    oracle--DG初始化参数
    oracle --工具 ODU
    Oracle RAC 修改SPFILE路径 文件查看
    oracle 错误 ORA-00020问题解析
    oracle 错误 TNS-01190与oracle 登入没反应操作
    Oracle--RMAN Recover 缺失的归档操作
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9959924.html
Copyright © 2011-2022 走看看