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


    题面

    传送门

    思路

    第一问:无脑网络流跑一波

    第二问:

    先考虑一个贪心的结论:扩容出来的扩容流量一定要跑满

    证明显然

    因此我们可以把扩容费用可以换个角度思考,变成增加一点流量,花费W的费用

    这样,我们就得到了一个最小费用流的模型

    只要在原图基础上,对于每个原图边,加一条费用为W,无限容量的边,而原图中的所有边费用为0,就可以模拟原题需要的情况了

    最后一个问题:流量增加限制K怎么处理?

    我们虽然可以用spfa的费用流,一次一次增加,直到K,但是这样也太慢chou了吧?

    不怕,我们加一个n+1号点,作为第二问的费用流汇点,在n到n+1之间连一条边,费用为0,流量为第一问的最大流流量加上K

    注意:上述算法是对于第二问建一个新图来跑的,对于在残量网络上瞎搞的方法,由于本人水平有限,并无法很好地证明正确性

    我的算法,时间复杂度大概会多一个$Oleft(m ight)$,再加上一点常数

    同时因为我是zkw费用流实现的最大流,所以大概稍慢....?

    其实应该是一样的吧!

    Code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define inf 1e9
    using namespace std;
    inline int read(){
        int re=0,flag=1;char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-') flag=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
        return re*flag;
    }
    int n,m,cnt=-1,ans,K,first[1010],dis[1010],vis[1010];
    struct edge{
        int to,next,w,cap;
    }a[25010];
    inline void add(int u,int v,int w,int cap){
        a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt;
        a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt;
    }
    bool spfa(int s,int t){
        int q[5010],head=0,tail=1,u,v,w,i;
        memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));
        q[0]=t;dis[t]=0;vis[t]=1;
        while(head<tail){
            u=q[head++];vis[u]=0;
            for(i=first[u];~i;i=a[i].next){
                v=a[i].to;w=a[i].w;
                if(a[i^1].cap&&((dis[v]==-1)||(dis[v]>dis[u]-w))){
                    dis[v]=dis[u]-w;
                    if(!vis[v]) q[tail++]=v,vis[v]=1;
                }
            }
        }
        return ~dis[s];
    }
    int dfs(int u,int t,int limit){
        if(u==t){vis[t]=1;return limit;}
        if(!limit){vis[u]=1;return 0;}
        int i,v,f,flow=0,w;vis[u]=1;
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;w=a[i].w;
            if((dis[v]==dis[u]-w)&&(!vis[v])&&a[i].cap){
                f=dfs(v,t,min(limit,a[i].cap));if(!f) continue;
                a[i].cap-=f;a[i^1].cap+=f;
                flow+=f;limit-=f;ans+=a[i].w*f;
                if(!limit) return flow;
            }
        }
        return flow;
    }
    int zkw(int s,int t){//zkw费用流
        int re=0;
        while(spfa(s,t)){
            vis[t]=1;
            while(vis[t]){
                memset(vis,0,sizeof(vis));
                re+=dfs(s,t,inf);
                //cout<<"cur re="<<re<<"
    ";
            }
        }
        return re;
    }
    int cost[5010],u[5010],v[5010],cap[5010];
    int main(){
        memset(first,-1,sizeof(first));
        int i,maxflow;
        n=read();m=read();K=read();
        for(i=1;i<=m;i++){
            u[i]=read();v[i]=read();cap[i]=read();cost[i]=read();
            add(u[i],v[i],0,cap[i]);
        }
        printf("%d ",maxflow=zkw(1,n));//maxflow要记录下来,后面有用
        memset(first,-1,sizeof(first));memset(a,0,sizeof(a));cnt=-1;//清理原图,重新建图
        for(i=1;i<=m;i++){
            add(u[i],v[i],0,cap[i]);
            add(u[i],v[i],cost[i],inf);
        }
        add(n,n+1,0,maxflow+K);
        zkw(1,n+1);
        printf("%d",ans);
    }
    
  • 相关阅读:
    差分隐私 differential privacy privSQL ||sql query ||sql查询系统||PrivateSQL:A Differentially Private SQL Query Engine论文笔记
    分冶法解决大整数相乘 最近对问题
    数论 矩阵交集
    STl 优先队列 C++
    备份mysql函数和存储过程
    Idea 注解模板
    excel导出
    帆软常用小技巧
    js + java文件下载
    try/finally
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8732901.html
Copyright © 2020-2023  润新知