• 【题解】Luogu P2604 [ZJOI2010]网络扩容


    原题传送门:P2604 [ZJOI2010]网络扩容

    这题可以说是板题

    给你一个图,先让你求最大流

    再告诉你,每条边可以花费一些代价,使得流量加一

    问至少花费多少代价才能使最大流达到k

    解法十分简单

    先跑一个dinic求最大流(我懒着写ISAP或前弧优化)

    再重新建图

    跑一个mcmf求最小费用最大流

    答案就出来了

    细节见代码

    #pragma GCC optimize("O3") 
    #include <bits/stdc++.h>
    #define maxn 10005
    #define maxm 50005
    #define inf 0x7f7f7f7f
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline int Min(register int a,register int b)
    {
        return a<b?a:b;
    }
    int n,m,k,tot,next[maxm<<1],beg[maxm<<1],head[maxn],flow[maxm<<1],fflow[maxm<<1],last[maxn],pre[maxn],fl[maxn],nxt[maxm<<1],to[maxm<<1],ccost[maxm<<1],cost[maxm<<1],d[maxn],dep[maxn];
    bool vis[maxn];
    inline void add(register int x,register int y,register int z,register int co,register int type)
    {
        nxt[++tot]=head[x];
        head[x]=tot;
        to[tot]=y;
        beg[tot]=x;
        flow[tot]=z;
        fflow[tot]=type?z:0;
        cost[tot]=type?co:0;
        ccost[tot]=co;
    }
    inline bool bfs()
    {
        memset(dep,0,sizeof(dep));
        queue<int> q;
        q.push(1);
        dep[1]=1;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(register int i=head[x];i;i=nxt[i])
            {
                int u=flow[i],v=to[i];
                if(u>0&&!dep[v])
                {
                    dep[v]=dep[x]+1;
                    q.push(v);
                }
            }
        }
        return dep[n];
    }
    inline int dfs(register int x,register int mini)
    {
        if(x==n)
            return mini;
        for(register int i=head[x];i;i=nxt[i])
        {
            int u=flow[i],v=to[i];
            if(u>0&&dep[v]==dep[x]+1)
            {
                int dd=dfs(v,Min(mini,u));
                if(dd>0)
                {
                    flow[i]-=dd;
                    flow[i^1]+=dd;
                    return dd;
                }
            }
        }
        return 0;
    }
    inline int dinic()
    {
        int ret=0;
        while(bfs())
        {
            int tmp=dfs(1,inf);
            while(tmp)
            {
                ret+=tmp;
                tmp=dfs(1,inf);
            }
        }
        return ret;
    }
    inline bool spfa()
    {
        memset(d,0x7f,sizeof(d));
        memset(fl,0x7f,sizeof(fl));
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(n+1);
        vis[n+1]=1;
        d[n+1]=0;
        pre[n]=-1;
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(register int i=head[now];i;i=nxt[i])
            {
                int v=to[i];
                if(fflow[i]>0&&d[v]>d[now]+cost[i])
                {
                    d[v]=d[now]+cost[i];
                    pre[v]=now;
                    last[v]=i;
                    fl[v]=Min(fl[now],fflow[i]);
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
            vis[now]=0;
        }
        return  pre[n]!=-1;
    }
    inline int mcmf()
    {
        int ret=0;
        while(spfa())
        {
            int now=n;
            ret+=fl[n]*d[n];
            while(now!=n+1)
            {
                fflow[last[now]]-=fl[n];
                fflow[last[now]^1]+=fl[n];
                now=pre[now];
            }
        }
        return ret;
    }
    inline void rebuild()
    {
        int cnt=tot;
        for(register int i=2;i<=cnt;i+=2)
        {
            fflow[i]=flow[i];
            fflow[i+1]=flow[i+1];
            add(beg[i],to[i],inf,ccost[i],1);
            add(to[i],beg[i],0,-ccost[i],1);
        }
    }
    int main()
    {
        n=read(),m=read(),k=read();
        add(n+1,1,k,0,1);
        for(register int i=1;i<=m;++i)
        {
            int a=read(),b=read(),c=read(),d=read();
            add(a,b,c,d,0),add(b,a,0,-d,0);
        }
        int ans1=dinic();
        rebuild();
        int ans2=mcmf();
        printf("%d %d",ans1,ans2);
        return 0;
    } 
    
  • 相关阅读:
    SQL——BETWEEN操作符
    SQL——IN操作符
    SQL——LIKE操作符
    SQL——ORDER BY关键字
    SQL——AND、OR运算符
    顺序执行
    流程控制
    集合类型
    字典类型
    字典 in 操作符
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/9734393.html
Copyright © 2020-2023  润新知