【题解】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;
} 
posted @ 2018-10-01 11:39  JSOI爆零珂学家yzhang  阅读(155)  评论(0编辑  收藏  举报