[ZJOI2010]网络扩容(费用流)
[ZJOI2010]网络扩容(费用流)
题面
给定一张有向图,每条边都有一个容量\(c\)和一个扩容费用\(w\)。这里扩容费用是指将容量扩大\(1\)所需的费用。求:
- 在不扩容的情况下,\(1\)到\(n\)的最大流;
- 将\(1\)到\(n\)的最大流增加\(k\)所需的最小扩容费用。
分析
先求出原图的最大流,大小设为\(f\)。对于原图中的每条边\((u,v,w)\),我们连边\((u,v,w,0)\)和\((u,v,+\infin,c)\),后面的那条边表示增加的流量。我们再连一条边\((n,n+1,f+k,0)\),表示流量增加\(k\)的限制。最后求\(1\)到\(n+1\)的最小费用最大流即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 10000
#define maxm 100000
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
namespace MAXF{
struct edge{
int from;
int to;
int next;
ll flow;
}E[maxm*2+5];
int head[maxn+5];
int cur[maxn+5];
int esz=1;
void add_edge(int u,int v,int w){
esz++;
E[esz].from=u;
E[esz].to=v;
E[esz].flow=w;
E[esz].next=head[u];
head[u]=esz;
esz++;
E[esz].from=v;
E[esz].to=u;
E[esz].flow=0;
E[esz].next=head[v];
head[v]=esz;
}
int deep[maxn+5];
bool bfs(int s,int t){
memset(deep,0,sizeof(deep));
queue<int>q;
q.push(s);
deep[s]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(!deep[y]&&E[i].flow){
deep[y]=deep[x]+1;
q.push(y);
}
}
}
return deep[t]>0;
}
ll dfs(int x,int t,ll minf){
if(x==t) return minf;
ll rest=minf,k;
for(int &i=cur[x];i;i=E[i].next){
int y=E[i].to;
if(E[i].flow&&deep[y]==deep[x]+1){
k=dfs(y,t,min(rest,E[i].flow));
E[i].flow-=k;
E[i^1].flow+=k;
rest-=k;
if(k==0) deep[y]=0;
if(rest==0) break;
}
}
return minf-rest;
}
ll dinic(int s,int t){
ll ans=0;
ll now=0;
while(bfs(s,t)){
memcpy(cur,head,sizeof(head));
while((now=dfs(s,t,INF))) ans+=now;
}
return ans;
}
}
namespace MCMF{
struct edge{
int from;
int to;
int next;
ll flow;
ll cost;
}E[maxm*2+5];
int head[maxn+5];
int esz=1;
void add_edge(int u,int v,ll w,ll c){
esz++;
E[esz].from=u;
E[esz].to=v;
E[esz].flow=w;
E[esz].cost=c;
E[esz].next=head[u];
head[u]=esz;
esz++;
E[esz].from=v;
E[esz].to=u;
E[esz].flow=0;
E[esz].cost=-c;
E[esz].next=head[v];
head[v]=esz;
}
ll dist[maxn+5],minf[maxn+5],last[maxn+5];
bool inq[maxn+5];
bool spfa(int s,int t){
queue<int>q;
memset(minf,0x3f,sizeof(minf));
memset(dist,0x3f,sizeof(dist));
memset(inq,0,sizeof(q));
q.push(s);
dist[s]=0;
inq[s]=1;
while(!q.empty()){
int x=q.front();
q.pop();
inq[x]=0;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(E[i].flow){
if(dist[y]>dist[x]+E[i].cost){
dist[y]=dist[x]+E[i].cost;
minf[y]=min(minf[x],E[i].flow);
last[y]=i;
if(!inq[y]){
inq[y]=1;
q.push(y);
}
}
}
}
}
if(dist[t]==INF) return 0;
else return 1;
}
void update(int s,int t){
int x=t;
while(x!=s){
int i=last[x];
E[i].flow-=minf[t];
E[i^1].flow+=minf[t];
x=E[i].from;
}
}
ll mcmf(int s,int t){
ll ct=0;
while(spfa(s,t)){
update(s,t);
ct+=dist[t]*minf[t];
}
return ct;
}
}
int n,m,K,s,t;
int main(){
// freopen("P3381_8.in","r",stdin);
int u,v,w,c;
scanf("%d %d %d",&n,&m,&K);
s=1,t=n;
for(int i=1;i<=m;i++){
scanf("%d %d %d %d",&u,&v,&w,&c);
MAXF::add_edge(u,v,w);
MCMF::add_edge(u,v,w,0);
MCMF::add_edge(u,v,INF,c);//扩容费用
}
ll maxflow=MAXF::dinic(s,t);
printf("%lld ",maxflow);
MCMF::add_edge(t,t+1,K+maxflow,0);//确保最大流增加了K
printf("%lld",MCMF::mcmf(s,t+1));
}
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢