[ZJOI2010]網路擴容(費用流)
阿新 • • 發佈:2020-07-28
[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)); }