您的位置:首页 > 理论基础 > 计算机网络

[ZJOI2010]网络扩容

2017-03-23 11:19 260 查看

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1


输出样例#1:

13 19


说明

30%的数据中,N<=100

100%的数据中,N<=1000,M<=5000,K<=10

数据规模并不准。

思路:最大流+构图+费用流

还是看了题解,构图的精髓没有掌握啊。

最大流:s->(q->z +w 0 -0 0)->t

费用流:ys-> (ys-> +k 0 -0 0)->s->残余免费网络||(q->z +k f -0 -f)->t

代码实现:

#include<cstdio>
#include<cstring>
const int inf=2139062143;
const int maxn=6000;
const int maxm=500000;
int n,m,k,s,t,ys,tw,tc;
int eq[maxn],ez[maxn],ew[maxn],ef[maxn];
int a,b,c,d;
inline int min_(int x,int y){return x<y?x:y;}
int h[maxn],hs=1;
struct edge{int s,n,w,f;}e[maxm];
void add(int q,int z,int w,int f){
e[++hs]=(edge){z,h[q],w,f},h[q]=hs;
e[++hs]=(edge){q,h[z],0,-f},h[z]=hs;
}
int de[maxn],q[maxm],head,tail;
bool bfs(){
memset(de,0,sizeof(de));
head=tail=0;
q[head++]=s,de[s]=1;
while(head>tail){
a=q[tail++];
for(int i=h[a];i;i=e[i].n)
if(!de[e[i].s]&&e[i].w){
de[e[i].s]=de[a]+1;
if(e[i].s==t) return true;
q[head++]=e[i].s;
}
}
return false;
}
int ap(int k,int w){
if(k==t) return w;
int uw=w;
for(int i=h[k];uw&&i;i=e[i].n)
if(de[e[i].s]==de[k]+1&&e[i].w){
int nw=ap(e[i].s,min_(uw,e[i].w));
if(nw) e[i].w-=nw,e[i^1].w+=nw,uw-=nw;
else de[e[i].s]=0;
}
return w-uw;
}
void Dinic(){while(bfs()) tw+=ap(s,inf);}
int w[maxn],pp[maxn],pw[maxn];
void spfa(){
memset(w,0x7f,sizeof(w));
head=tail=0;
q[head++]=ys,w[ys]=0;
while(head>tail){
a=q[tail++];
for(int i=h[a];i;i=e[i].n)
if(e[i].w&&1ll+w[a]+e[i].f-1<w[e[i].s]){
pp[e[i].s]=a,pw[e[i].s]=i;
q[head++]=e[i].s;
w[e[i].s]=w[a]+e[i].f;
}
}
}
int mcmf(int k,int v){
if(k==ys) return v;
int ret=mcmf(pp[k],min_(e[pw[k]].w,v));
e[pw[k]].w-=ret;
e[pw[k]^1].w+=ret;
return ret;
}
bool Cost(){
spfa();
if(w[t]==inf) return false;
tc+=w[t]*mcmf(t,inf);
}
int main(){
freopen("networkzj2010.in","r",stdin);
freopen("networkzj2010.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
s=1,t=n;
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&eq[i],&ez[i],&ew[i],&ef[i]);
add(eq[i],ez[i],ew[i],0);
}
Dinic();
ys=0,add(ys,s,k,0);
for(int i=1;i<=m;i++) add(eq[i],ez[i],k,ef[i]);
while(Cost());
printf("%d %d\n",tw,tc);
return 0;
}


题目来源:洛谷
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: