[网络流] bzoj1834: [ZJOI2010]network 网络扩容

bzoj1834: [ZJOI2010]network 网络扩容 http://www.lydsy.com/JudgeOnline/problem.php?id=1834

最大流+费用流
第一问直接跑最大流这个很简单
第二问好像很复杂的样纸……
因为原来的图里面有残余的流量所以如果把这些流量也能用上的话费用就会小很多
所以直接在原来跑完最大流的图的基础上再建上容量为k费用为w的边
再建多一个超级汇源 边的容量为k 限制增加流量为k
然后跑费用流就可以了
不看题解真的不会做
机房大佬的题解:https://www.cnblogs.com/Never-mind/p/8150382.html

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node1
{
    int x,y,c,cost,next,other;
}a[21000];
int last[1100],len;
int x[5100],y[5100],c[5100],w[5100];
int dep[11000],f[11000],pre[11000];
int st,ed,edx,list[1100000];
bool v[1100];
int ans=0;
void build(int x,int y,int c,int cost)
{
    len++;int k1=len;
    a[len].x=x;a[len].y=y;a[len].c=c;a[len].cost=cost;a[len].next=last[x];last[x]=len;
    len++;int k2=len;
    a[len].x=y;a[len].y=x;a[len].c=0;a[len].cost=-cost;a[len].next=last[y];last[y]=len;
    a[k1].other=k2;a[k2].other=k1;
}
bool bfs()
{
    memset(dep,0,sizeof(dep));
    int head=1,tail=1;
    list[1]=st;dep[st]=1;
    while (head<=tail)
    {
        int x=list[head];
        for (int k=last[x];k;k=a[k].next) 
        {
            int y=a[k].y;
            if (dep[y]==0&&a[k].c>0)
            {
                dep[y]=dep[x]+1;
                list[++tail]=y;
            }
        }
        head++;
    }
    if (dep[ed]==0) return 0;
    else return 1;
}
int dfs(int x,int flow)
{
    if (x==ed) return flow;
    int tot=0,sum=0;
    for (int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if (dep[y]==dep[x]+1&&a[k].c>0&&flow>tot)
        {
            sum=dfs(y,min(flow-tot,a[k].c));
            tot+=sum;a[k].c-=sum;a[a[k].other].c+=sum;
        }
    }
    if (tot==0) dep[x]=0;
    return tot;
}
bool spfa()
{
    memset(v,false,sizeof(v));
    memset(f,63,sizeof(f));
    int head=1,tail=1;
    list[1]=st;v[st]=true;
    f[st]=0;
    while (head<=tail)
    {
        int x=list[head];
        for (int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if (f[y]>f[x]+a[k].cost&&a[k].c>0)
            {
                f[y]=f[x]+a[k].cost;
                pre[y]=k;
                if (v[y]==false)
                {
                    v[y]=true;
                    list[++tail]=y;
                }
            }
        }
        head++;
        v[x]=false;
    }
    if (f[edx]>=999999999) return false;
    else
    {
        int x=edx,minn=999999999;
        ans+=f[edx];
        while (x!=st)
        {
            int k=pre[x];
            a[k].c--;
            a[a[k].other].c++;
            x=a[k].x;
        }
        return true;
    }
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++) 
    {
        scanf("%d%d%d%d",&x[i],&y[i],&c[i],&w[i]);
        build(x[i],y[i],c[i],0);
    }
    st=n+1;ed=n+2;
    build(st,1,999999999,0);
    build(n,ed,999999999,0);
    while (bfs())
    {
        ans+=dfs(st,999999999);
    }
    printf("%d ",ans);
    for (int i=1;i<=m;i++)
    {
        build(x[i],y[i],k,w[i]);
    }
    edx=ed+1;
    build(n,edx,k,0);//限制为k 
    ans=0;
    while (spfa()) {}
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值