BZOJ 1834 【ZJOI2010】 network 网络扩容

Description

给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。

Input

输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。

Output

输出文件一行包含两个整数,分别表示问题1和问题2的答案。

HINT

30%的数据中,N<=100

100%的数据中,N<=1000,M<=5000,K<=10
 
  网络流与费用流二合一233~
  首先第一问显然没有什么好讲的,直接跑一遍最大流即可。
  接下来是第二问。既然$k$这么小,那么我们保留下跑最大流后的残量网络,显然残量网络中有流量的边都是有可以直接流的,并且不需要任何费用。
  然后我们对于原图中的每一条边,新建一条容量为$inf$,费用为扩容费用 的边。接下来新建一个源点,向$1$号点连一条容量为$k$,费用为$0$的边,控制一下流量。
  最后跑一遍最小费用最大流即可。
  下面贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 1010
#define maxm 20010
#define INF (1<<25)

using namespace std;
typedef long long llg;

struct data{
	int u,v,c,w;
}s[maxm];
int n,m,K,d[maxn],dep[maxn],ans,S,fa[maxn];
int head[maxn],next[maxm],to[maxm],c[maxm],f[maxm],tt=1;
bool w[maxn];

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>'9'||c<'0')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),q=1;
	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
	return q?-w:w;
}

bool bfs(){
	int l=0,r=0;
	for(int i=1;i<=n;i++) dep[i]=-1;
	dep[1]=1; d[r++]=1;
	while(l!=r){
		int u=d[l++];
		for(int i=head[u],v;v=to[i],i;i=next[i])
			if(c[i] && dep[v]==-1) dep[v]=dep[u]+1,d[r++]=v;
	}
	return dep[n]!=-1;
}

int dfs(int u,int now){
	if(u==n) return now;
	if(!now) return 0;
	int low=0;
	for(int i=head[u],v,res;v=to[i],i;i=next[i])
		if(c[i] && dep[v]==dep[u]+1){
			res=dfs(v,min(now,c[i])); low+=res;
			c[i]-=res; c[i^1]+=res; now-=res;
		}
	if(!low) dep[u]=-1;
	return low;
}

bool spfa(){
	int l=0,r=0;
	for(int i=1;i<=n;i++) dep[i]=-1,w[i]=0;
	dep[S]=0; d[r++]=S; w[S]=1;
	while(l!=r){
		int u=d[l++]; w[u]=0; if(l==maxn) l=0;
		for(int i=head[u],v;v=to[i],i;i=next[i])
			if(c[i] && (dep[v]==-1 || dep[v]>dep[u]+f[i])){
				dep[v]=dep[u]+f[i]; fa[v]=i;
				if(!w[v]){
					d[r++]=v; w[v]=1;
					if(r==maxn) r=0;
				}
			}
	}
	return dep[n]!=-1;
}

int get(){
	int now=INF,ans=0;
	for(int u=n;u!=S;u=to[fa[u]^1]) now=min(now,c[fa[u]]),ans+=f[fa[u]];
	for(int u=n;u!=S;u=to[fa[u]^1]) c[fa[u]]-=now,c[fa[u]^1]+=now;
	return now*ans;
}

int main(){
	File("a");
	n=getint(); m=getint(); K=getint();
	for(int i=1,u,v;i<=m;i++){
		s[i].u=getint(),s[i].v=getint();
		s[i].c=getint(),s[i].w=getint();
		u=s[i].u; v=s[i].v;
		to[++tt]=v;next[tt]=head[u];head[u]=tt;
		to[++tt]=u;next[tt]=head[v];head[v]=tt;
		c[tt-1]=s[i].c;
	}
	while(bfs()) ans+=dfs(1,INF);
	printf("%d",ans);
	for(int i=1,u,v;i<=m;i++){
		u=s[i].u,v=s[i].v;
		to[++tt]=v;next[tt]=head[u];head[u]=tt;
		to[++tt]=u;next[tt]=head[v];head[v]=tt;
		c[tt-1]=INF; f[tt-1]=s[i].w; f[tt]=-s[i].w;
	}
	S=n+1; ans=0;
	to[++tt]=1;next[tt]=head[S];head[S]=tt; c[tt]=K;
	to[++tt]=S;next[tt]=head[1];head[1]=tt;
	while(spfa()) ans+=get();
	printf(" %d",ans);
	return 0;
}
posted @ 2016-11-11 19:48  lcf2000  阅读(180)  评论(0编辑  收藏  举报