zoukankan      html  css  js  c++  java
  • [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));
    } 
    
  • 相关阅读:
    如何实现Iframe透明
    ListView(未完)
    我又回来了
    前言
    代码重用and思路重用
    图片上传
    千万数量级分页存储过程
    MSSQL中,将text,ntext转换为int型数据
    优秀的回复,来自圣殿骑士
    SqlDataSource控件
  • 原文地址:https://www.cnblogs.com/birchtree/p/13389439.html
Copyright © 2011-2022 走看看