[ ZJOI 2010 ] 网络扩容

\(\\\)

Description


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

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

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

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

  • \(n\le 10^3,m\le 5\times 10^3,K\le 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\n",mcmf(k).second);
  return 0;
}
posted @ 2018-11-14 19:39  SGCollin  阅读(157)  评论(0编辑  收藏  举报