BZOJ 1834 [ZJOI2010]network 网络扩容

starli posted @ 2016年5月02日 14:41 in 网络流 , 684 阅读

网络流裸体 

第一问最大流跑一跑

第二问新建一个点连边到1 容量k费用0 再对所有的边复制一条边出来 容量为inf 费用为w

然后跑最小费用最大流

这题最大流用ek可过

#include <cstdio>
#include <algorithm>
#include <cstring>
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
void read(int &x){
	char c;
	while((c=getchar())<'0' || c>'9');x=c-'0';
	while((c=getchar())>='0' && c<='9') x=x*10+c-'0';
}
const int N=100010,inf=308888888;
struct Ask{
	int u,v,c,w;
	void read2(){read(u),read(v);read(c);read(w);}
}ask[N];
int n,m,c[N],to[N],nxt[N],now[N],cap[N],tail=1,q[N],from[N],dis[N],inq[N],k,ans;
void add(int u,int v,int ci,int capi){
	to[++tail]=v;nxt[tail]=now[u];now[u]=tail;c[tail]=ci;cap[tail]=capi;
	to[++tail]=u;nxt[tail]=now[v];now[v]=tail;c[tail]=-ci;cap[tail]=0;
}
bool spfa(int s,int t){
	int l=0,r=0;
	clr(from);clr(inq);
	for(int i=1;i<=n+2;i++) dis[i]=inf;
	q[++r]=s;dis[s]=0;inq[s]=1;
	while(l<r){
		int u=q[(++l)%N];inq[u]=0;
		for(int i=now[u];i;i=nxt[i]) if(cap[i]>0 && dis[to[i]]>dis[u]+c[i]){
			int v=to[i];
			dis[v]=dis[u]+c[i];
			from[v]=i;
			if(!inq[v]) q[(++r)%N]=v;
		}
	}
	return dis[t]!=inf;
}
int augument(int s,int t,int type){
	int fl=inf,ret=0;
	for(int tmp=t;tmp!=s;){
		int e=from[tmp];
		fl=min(cap[e],fl);
		tmp=to[e^1];
	}
	for(int tmp=t;tmp!=s;){
		int e=from[tmp];
		cap[e]-=fl;cap[e^1]+=fl;
		ret+=fl*c[e];
		tmp=to[e^1];
	}
	return type?ret:fl;
}
int main(){
	//freopen("1834.in","r",stdin);freopen("1834.out","w",stdout);
	read(n);read(m);read(k);
	for(int i=1;i<=m;i++) {
		ask[i].read2();
		add(ask[i].u,ask[i].v,0,ask[i].c);
	}
	while(spfa(1,n)) ans+=augument(1,n,0);
	printf("%d ",ans);ans=0;
	for(int i=1;i<=m;i++) add(ask[i].u,ask[i].v,ask[i].w,inf);
	add(n+1,1,0,k);
	while(spfa(n+1,n)) 	ans+=augument(n+1,n,1);
	printf("%d",ans);
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter