【BZOJ1834】网络扩容(ZJOI2010)-最大流+费用流+拆边

测试地址:网络扩容
做法:本题需要用到最大流+费用流+拆边。
首先第一问直接做最大流就行了,记得到的答案为maxf,主要是第二问。我们发现原网络中的边的费用可以用一个分段函数表示,即当流量超过原容量时,费用为超出部分乘上扩容费用,显然我们可以把这条边拆成一条容量为原容量,费用为0的边和一条容量为正无穷,费用为扩容费用的边。这个网络有一个非常明显的问题,那就是它的最大流并不是我们要求的maxf+k,这要怎么办呢?非常简单,只用从点n连一条容量为maxf+k,费用为0的边到一个超级汇点上,这样从点1到超级汇点的最大流就一定是maxf+k了,这样我们就做一个最小费用最大流即可。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,m,S,T,k,u[5010],v[5010],w[5010];
int first[1010]={0},tot=1;
int lvl[1010],cur[1010];
int dis[1010],laste[1010],last[1010];
bool vis[1010];
queue<int> Q;
struct edge
{
    int v,next,f,c;
}e[100010];

void insert(int a,int b,int f,int c)
{
    e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,e[tot].c=c,first[a]=tot;
    e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,e[tot].c=-c,first[b]=tot;
}

void init()
{
    scanf("%d%d%d",&n,&m,&k);
    S=1,T=n;
    for(int i=1;i<=m;i++)
    {
        int c;
        scanf("%d%d%d%d",&u[i],&v[i],&c,&w[i]);
        insert(u[i],v[i],c,0);
    }
}

bool makelevel()
{
    for(int i=1;i<=T;i++)
        lvl[i]=-1,cur[i]=first[i];
    lvl[S]=0;
    Q.push(S);
    while(!Q.empty())
    {
        int v=Q.front();Q.pop();
        for(int i=first[v];i;i=e[i].next)
            if (e[i].f&&lvl[e[i].v]==-1)
            {
                lvl[e[i].v]=lvl[v]+1;
                Q.push(e[i].v);
            }
    }
    return lvl[T]!=-1;
}

int maxflow(int v,int maxf)
{
    if (v==T) return maxf;
    int ret=0,f;
    for(int i=cur[v];i;i=e[i].next)
    {
        if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
        {
            f=maxflow(e[i].v,min(maxf-ret,e[i].f));
            ret+=f;
            e[i].f-=f;
            e[i^1].f+=f;
            if (ret==maxf) break;
        }
        cur[v]=i;
    }
    if (!ret) lvl[v]=-1;
    return ret;
}

void dinic()
{
    int maxf=0;
    while(makelevel())
        maxf+=maxflow(S,inf);
    printf("%d ",maxf);
}

void init2()
{
    T=n+1;
    insert(n,T,k,0);
    for(int i=1;i<=m;i++)
        insert(u[i],v[i],inf,w[i]);
}

bool spfa()
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=T;i++)
        dis[i]=inf;
    dis[S]=0;
    vis[S]=1;
    Q.push(S);
    while(!Q.empty())
    {
        int v=Q.front();Q.pop();
        for(int i=first[v];i;i=e[i].next)
            if (e[i].f&&dis[e[i].v]>dis[v]+e[i].c)
            {
                dis[e[i].v]=dis[v]+e[i].c;
                laste[e[i].v]=i;
                last[e[i].v]=v;
                if (!vis[e[i].v]) vis[e[i].v]=1,Q.push(e[i].v);
            }
        vis[v]=0;
    }
    return dis[T]!=inf;
}

void mincost()
{
    int minc=0;
    while(spfa())
    {
        int x=T,maxf=inf;
        while(x!=S)
        {
            maxf=min(maxf,e[laste[x]].f);
            x=last[x];
        }
        x=T;
        while(x!=S)
        {
            e[laste[x]].f-=maxf;
            e[laste[x]^1].f+=maxf;
            x=last[x];
        }
        minc+=maxf*dis[T];
    }
    printf("%d",minc);
}

int main()
{
    init();
    dinic();
    init2();
    mincost();

    return 0;
}
posted @ 2018-04-29 14:21  Maxwei_wzj  阅读(115)  评论(0编辑  收藏  举报