bzoj1834 网络扩容 网络流

好久没写题解了啊···

题目大意:

给你一幅n个点的网络,先求出其1到n的最大流,每条弧还会有个属性\(cost_i\),表示没扩容一个单位的费用,现在我们要求的就是扩容K个单位的最小费用

思路:

这是一道比较裸的网络流,第一问直接dinic就是了,重点就在于第二问。我们把第一问的残量网络继续利用,其中的每条弧的费用都是0,此时我们再在第\(i\)条弧的两端之间在建一条弧,弧的容量是\(INF\),费用就是\(cost_i\)。这样我们固然可以保证费用正确,可是我们保证不了扩容了K,我们就可以建一个超级源点,连向1号点,容量为K,费用为0。在这个网络中最大流一定是满流,也就是K啊,此时的最小费用就是我们所要求的。

具体实现:

这就很简单了,一遍\(dinic\),再一遍\(MCMF\)我们就可以了
代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;

const int maxn=10001,maxm=50001,inf=0x7f7f7f7f;
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];

void addedge(int x,int y,int z,int co,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;
}

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(int i=head[x];i;i=nxt[i]){
            int u=flow[i],v=to[i];
            if(u>0 and !dep[v]){
                dep[v]=dep[x]+1;
                q.push(v);
            }
        }
    }
    return dep[n];
}

int dfs(int x,int mini){
    if(x==n)return mini;
    for(int i=head[x];i;i=nxt[i]){
        int u=flow[i],v=to[i];
        if(u>0 and 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;
}

int dinic(){
    int ret=0;
    while(bfs()){
        int tmp=dfs(1,inf);
        while(tmp){
            ret+=tmp;
            tmp=dfs(1,inf);
        }
    }
    return ret;
}

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(int i=head[now];i;i=nxt[i]){
            int v=to[i];
            if(fflow[i]>0 and 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;
}

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;
}

void rebuild(){
    int cnt=tot;
    for(int i=2;i<=cnt;i+=2){
        fflow[i]=flow[i];
        fflow[i+1]=flow[i+1];
        addedge(beg[i],to[i],inf,ccost[i],1);
        addedge(to[i],beg[i],0,-ccost[i],1);
    }
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    addedge(n+1,1,k,0,1);
    for(int i=1;i<=m;i++){
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        addedge(a,b,c,d,0);
        addedge(b,a,0,-d,0);
    }
    int ans1=dinic();
    rebuild();
    int ans2=mcmf();
    printf("%d %d\n",ans1,ans2);
    return 0;
}

原文地址:https://www.cnblogs.com/ezoihy/p/9417308.html

时间: 2024-10-04 11:06:27

bzoj1834 网络扩容 网络流的相关文章

[ZJOI2010][bzoj1834] 网络扩容 [费用流]

题面 传送门 思路 第一问:无脑网络流跑一波 第二问: 先考虑一个贪心的结论:扩容出来的扩容流量一定要跑满 证明显然 因此我们可以把扩容费用可以换个角度思考,变成增加一点流量,花费W的费用 这样,我们就得到了一个最小费用流的模型 只要在原图基础上,对于每个原图边,加一条费用为W,无限容量的边,而原图中的所有边费用为0,就可以模拟原题需要的情况了 最后一个问题:流量增加限制K怎么处理? 我们虽然可以用spfa的费用流,一次一次增加,直到K,但是这样也太慢chou了吧? 不怕,我们加一个n+1号点,

bzoj1834: [ZJOI2010]network 网络扩容

努力看了很久样例一直过不了...然后各种输出中间过程啊巴拉巴拉弄了1h,没办法了...然后突然想到啊原来的边可以用啊为什么不用...于是A了...感人肺腑 #include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n

C++之路进阶——网络流(网络扩容)

1362 网络扩容 省队选拔赛 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1.  在不扩容的情况下,1到N的最大流: 2.  将1到N的最大流增加K所需的最小扩容费用. 输入描述 Input Description 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含

bzoj 1834: [ZJOI2010]network 网络扩容 -- 最大流+费用流

1834: [ZJOI2010]network 网络扩容 Time Limit: 3 Sec  Memory Limit: 64 MB Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. Input 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一

网络工程师成长日记383-某银行某市中心支行市县网络扩容项目工程感想

这是我的第383篇原创文章,记录网络工程师行业的点点滴滴,结交IT行业有缘之人 某银行某市中心支行市县网络扩容项目工程感想 接到老大短信告知有项目后,当时正好在我奋战了2个月的08机房聊天随即跑到老大那了解情况后回家取了相机和笔记本赶来COPY了安工的两个华为的技术文档(后来正是这两个文档帮了我的大忙,看来技术准备工作必须做充分,要不就得卡壳)就速速赶往锦诚网络和第二方(这里用第二方这么冠冕的词是因为我后面遇到了第四方)联系人接头,接上头后被告知要等第三方派车来接到某市调试等了半个小时后,第三方

【BZOJ1834】network 网络扩容(最大流,费用流)

题意:给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用. 求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 30%的数据中,N<=100 100%的数据中,N<=1000,M<=5000,K<=10 思路:RYZ作业 第一问最大流即可 第二问网上很多题解都是在第一问的残余网络上构图,但是根本不需要 考虑边(x,y,z,w) 有容量为z,费用为0的免费流量,有容量为INF,费用为w的扩容付费流

【bzoj1834】[ZJOI2010]network 网络扩容 最大流+最小费用流

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 样例输入 5 8 2 1 2 5 8 2 5 9

bzoj1834 ZJOI2010网络扩容(费用流)

给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用. 求: 1.在不扩容的情况下,1到N的最大流: 2.将1到N的最大流增加K所需的最小扩容费用. 其中\(n \le 1000,m \le 5000,k \le 10\) 网络流题,复杂度都是没用的了.... 第一问就是一个裸的最大流 现在我们考虑第二问QwQ 最小扩容费用,我们是不是可以对于原图中的\(u->v\)的边,添加一条\(u->v\),流量为\(inf\),费用为\(w\)的边,这样就可以实

bzoj1834: [ZJOI2010]network 网络扩容

这道题分为俩步,第一是求最大流,第二是在第一问的残量网络上求最小费用流. 建图时俩个点直接连2条边,一条容量为f[i],费用为0,另一条容量为inf,费用为c[i].这样就可以跑俩个算法了 第二问设一个虚拟源点S与1连容量为k,费用为0的边,n与一个虚拟汇点T连容量为k,费用为0的边.这样一直跑,最后只会增加k的流量. 记住bool一定要用true和false,用0和1tle了..不知道为啥,但一定要记住 #include<cstdio> #include<algorithm> #