• [HAOI2010][bzoj2424] 订货 [费用流]


    题面

    传送门

    思路

    这题其实挺水的......做过餐巾计划问题就能明白,是同一个道理

    首先,显然刚刚好满足每一个月的需求,会得到最优解(废话-_-||)

    然后我们发现,货物在不同的月之间的转移,可以比喻为水在不同的几个平行管道之间流动

    自然而然地想到网络流

    那么,我们给每个月建立一个节点i,建立超级源点和超级汇点

    从每个i连边(i,T),费用0,流量为这个月需求量

    从S向每个月连边(S,i),费用为这个月的价格,流量无限(因为理论上你随便买都可以)

    那么储存就是连边(i,i+1),费用为m,流量为S,这里的流量也很好地体现了限制作用

    最后的答案就是(S-T)最小费用最大流了

    需要注意的是,这道题里面的流量提供了两个限制:

    一个是每个月可以买很多,但是我们输出只有要求的那么多,是一个下限转上限

    另一个就是仓库容量,这个是直接把上限用流量表示出来了

    由此,我们应当注意到,网络流中的流量上限其实不止可以表示一种决策的最大值

    它也可以在一定的贪心和推导以后来表示最小值

    所以做题的时候思路一定要大胆一些

    说不定这就是个网络流题呢?

    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 first[5010],dis[5010],vis[5010],n,m,cnt=-1,ans;
    struct edge{
        int to,next,w,cap;
    }a[600010];
    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;
    }
    int q[1000010];
    bool spfa(int s,int t){
        int head=0,tail=1,i,u,v,w;
        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 _min(int l,int r){return (l>r)?r:l;}
    int dfs(int u,int t,int limit){
        if((u==t)||(!limit)){vis[u]=1;return limit;}
        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&&a[i].cap&&!vis[v]){
                if(!(f=dfs(v,t,_min(limit,a[i].cap)))) continue;
                a[i].cap-=f;a[i^1].cap+=f;
                ans+=f*w;flow+=f;limit-=f;
                if(!limit) return flow;
            }
        }
        return flow;
    }
    int zkw(int s,int t){
        int re=0;
        while(spfa(s,t)){
            vis[t]=1;
            while(vis[t]){
                memset(vis,0,sizeof(vis));
                re+=dfs(s,t,inf);
            }
        }
        return re;
    }
    int main(){
        memset(first,-1,sizeof(first));
        n=read();m=read();int S=read(),i,t1;
        for(i=1;i<=n;i++) t1=read(),add(i,n+1,0,t1);
        for(i=1;i<=n;i++) t1=read(),add(0,i,t1,inf);
        for(i=1;i<n;i++) add(i,i+1,m,S);
        zkw(0,n+1);
        cout<<ans<<endl;
    }
    
  • 相关阅读:
    git版本回退问题记录
    git add的各种情况分类
    代码优化积累【持续更新】
    package.json和package-lock.json的区别
    new Date在IE下面兼容问题
    git fetch和git pull的区别
    Node.Js的热更新服务——supervisor
    springboot 指定启动环境
    java后台解决上传图片翻转90的问题,有demo,经过测试可用
    intellij IDEA 实用快捷键
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8746582.html
Copyright © 2020-2023  润新知