[ZJOI2010]网络扩容(费用流)

[ZJOI2010]网络扩容(费用流)

题面

给定一张有向图,每条边都有一个容量\(c\)和一个扩容费用\(w\)。这里扩容费用是指将容量扩大\(1\)所需的费用。求:

  1. 在不扩容的情况下,\(1\)\(n\)的最大流;
  2. \(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));
} 
posted @ 2020-07-28 09:59  birchtree  阅读(146)  评论(0编辑  收藏  举报