[ 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;
}