• BZOJ_1834_[ZJOI2010]network 网络扩容_费用流


    BZOJ_1834_[ZJOI2010]network 网络扩容_费用流

    题意:

    给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
    求: 
    1、在不扩容的情况下,1到N的最大流; 
    2、将1到N的最大流增加K所需的最小扩容费用。
     
    分析:
    第一问直接最大流。
    第二问我们对于每条边,连一个容量不变,费用为0的表示不花钱能通过一些流量
    再连一个容量无限,费用为扩容费用的边表示要想扩容必须花钱
    再限制最大流为k,新建源点,源点向1连容量为k的边
    跑最小费用最大流即可。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 2050
    #define M 60050
    #define inf 100000000
    #define S (n+1)
    #define T (n+2)
    int head[N],to[M],nxt[M],flow[M],val[M],path[M],cnt=1;
    int n,m,k,Q[N],l,r,dep[N],inq[N];
    int xx[M],yy[M],cc[M],ww[M],dis[N];
    inline void add1(int u,int v,int f)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
    }
    inline void add2(int u,int v,int f,int c)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;val[cnt]=c;
    }
    bool bfs()
    {
        memset(dep,0,sizeof(dep));
        l=r=0;
        dep[1]=1;
        Q[r++]=1;
        int i;
        while(l^r)
        {
            int x=Q[l++];if(l==n+1)l=0;
            for(i=head[x];i;i=nxt[i])if(!dep[to[i]]&&flow[i])
            {
                dep[to[i]]=dep[x]+1;
                if(to[i]==n)return 1;
                Q[r++]=to[i];if(r==n+1)r=0;
            }
        }
        return 0;
    }
    int dfs(int x,int mf)
    {
        if(x==n)return mf;
        int nf=0;
        int i;
        for(i=head[x];i;i=nxt[i])if(dep[to[i]]==dep[x]+1&&flow[i])
        {
            int tmp=dfs(to[i],min(flow[i],mf-nf));
            nf+=tmp;
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            if(nf==mf)break;
        }
        dep[x]=0;
        return nf;
    }
    bool spfa()
    {
        memset(dis,0x3f,sizeof(dis));
        memset(path,0,sizeof(path));
        l=r=0;
        int i;
        Q[r++]=S;dis[S]=0;inq[S]=1;
        while(l^r)
        {
            int x=Q[l++];if(l==n+4)l=0;inq[x]=0;
            for(i=head[x];i;i=nxt[i])
            {
                if(flow[i]>0&&dis[to[i]]>dis[x]+val[i])
                {
                    dis[to[i]]=dis[x]+val[i];
                    path[to[i]]=i^1;
                    if(!inq[to[i]])
                    {
                        inq[to[i]]=1;
                        Q[r++]=to[i];
                        if(r==n+4)r=0;
                    }
                }
            }
        }
        return dis[T]<inf;
    }
    void mcmf()
    {
        int mnc=0,mxf=0,i;
        while(spfa())
        {
            int nf=1<<30;
            for(i=T;i!=S;i=to[path[i]])
            {
                nf=min(nf,flow[path[i]^1]);
            }
            for(i=T;i!=S;i=to[path[i]])
            {
                flow[path[i]]+=nf;
                flow[path[i]^1]-=nf;
                mnc+=val[path[i]^1]*nf;
            }
            mxf+=nf;
        }
        printf("%d
    ",mnc);
    }
    void dinic()
    {
        int ans=0,f;
        while(bfs())
        {
            while(f=dfs(1,inf))
                ans+=f;
        }
        k+=ans;
        printf("%d ",ans);
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        int i;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&xx[i],&yy[i],&cc[i],&ww[i]);
            add1(xx[i],yy[i],cc[i]);
            add1(yy[i],xx[i],0);
        }
        dinic();
        cnt=1;
        memset(head,0,sizeof(head));
        add2(S,1,k,0);
        add2(1,S,0,0);
        add2(n,T,k,0);
        add2(T,n,0,0);
        for(i=1;i<=m;i++)
        {
            add2(xx[i],yy[i],cc[i],0);
            add2(yy[i],xx[i],0,0);
            add2(xx[i],yy[i],inf,ww[i]);
            add2(yy[i],xx[i],0,-ww[i]);
        }
        mcmf();
    }
    

      

  • 相关阅读:
    读 《异类》- 作者:[加拿大] 马尔科姆·格拉德威尔 有感
    docker常用操作命令
    MySQL 使用规范
    js 字符串转json对象
    Mybatis 工作原理
    JDBC连接配置
    Java 线程基础
    数组与链表
    Java 内部类
    MySQL 去重
  • 原文地址:https://www.cnblogs.com/suika/p/8551831.html
Copyright © 2020-2023  润新知