zoukankan      html  css  js  c++  java
  • [网络流24题(2/24)] 餐巾计划问题 (洛谷P1251)最小费用最大流

    传送门

    题意:

    现在有$N$天,第$i$天需要使用$a_i$个新的餐巾,新餐巾用完后,可以花费$f$元使得第$i+m$天后可以重新利用;可以花费$s$元使得第$i+n$天后可以使用;也可以把旧餐巾留到下一天去洗。

    现在买一个新的餐巾需要$p$元,现在问你在满足所有天的要求的前提下的最小花费。

    分析:

    一个比较厉害的最小费用最大流的模型。

    看到即涉及物品的(物品还能流动的),又涉及最小费用的往费用流上考虑?

    首先需要知道,在这$N$天中,餐巾是会不断的移动的,我们试着把餐巾的移动路线分析一下:

    我们发现,对于每一天,存在着旧餐巾和新餐巾两种叠加的状态,因此我们考虑把一天拆成两个点(分别为旧餐巾和新餐巾)分别来考虑。

    对于第$i$天的旧餐巾:

    1. 它能够走向第$i+1$的旧餐巾处,无花费
    2. 它能够通过花费$f$元,重新洗涤,到达第$i+m$天的新餐巾处
    3. 它能够通过花费$s$元,重新洗涤,到达第$i+n$天的新餐巾处

    对于第$i$天的新餐巾:

    1. 它能通过花费$p_i$元,从源点购买$a_i$个全新的餐巾。
    2. 它能通过$i-m$天的旧餐巾洗涤过来。
    3. 它能通过$i-n$天的旧餐巾洗涤过来。

    而我们发现,对于旧餐巾,它每天都是会通过某种途径源源不断的获取$a_i$的旧餐巾(因为每天都会有新餐巾用完变成旧餐巾)。而上述并没有流向旧餐巾的状态,因此我们考虑从源点向每一天的旧餐巾的状态连接一条容量为$a_i$,花费为$0$的边。

    同时,我们发现,新餐巾是远远不断的送出餐巾,同理,我们考虑从每天的新餐巾向汇点连接一天容量为$a_i$,花费为$0$的边,这条边代表着每天都会使用掉$a_i$个餐巾。

    而按照我们上述建出来的图,显然是满足流量平衡的,因此,当我们使这张图获取到最大流时,即可满足每一天的餐巾需求均能够被满足。

    之后我们只需要在这个基础上跑一遍最小费用最大流即是答案。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn =5005;
    const int maxm=500005;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    int head[maxn],cnt=0;
    int vis[maxn],sp,ep;
    ll maxflow,cost,dis[maxn];
    struct Node{
        int to,next;
        ll val,cost;
    }q[maxm<<1];
    void init(){
        memset(head,-1,sizeof(head));
        cnt=2;
        maxflow=cost=0;
    }
    void addedge(int from,int to,ll val,ll cost){
        q[cnt].to=to;
        q[cnt].next=head[from];
        q[cnt].val=val;
        q[cnt].cost=cost;
        head[from]=cnt++;
    }
    void add_edge(int from,int to,ll val,ll cost){
        addedge(from,to,val,cost);
        addedge(to,from,0,-cost);
    }
    bool spfa(){
        memset(vis,0,sizeof(vis));
        memset(dis,inf,sizeof(dis));
        dis[sp]=0;
        vis[sp]=1;
        queue<int>que;
        que.push(sp);
        while(!que.empty()){
            int x=que.front();
            que.pop();
            vis[x]=0;
            for(int i=head[x];i!=-1;i=q[i].next){
                int to=q[i].to;
                if(dis[to]>dis[x]+q[i].cost&&q[i].val){
                    dis[to]=dis[x]+q[i].cost;
                    if(!vis[to]){
                        que.push(to);
                        vis[to]=1;
                    }
                }
            }
        }
        return dis[ep]!=inf;
    }
    ll dfs(int x,ll flow){
        if(x==ep){
            vis[ep]=1;
            maxflow+=flow;
            return flow;
        }//可以到达t,加流
        ll used=0;//该条路径可用流量
        vis[x]=1;
        for(int i=head[x];i!=-1;i=q[i].next){
            int to=q[i].to;
            if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){
                ll minflow=dfs(to,min(flow-used,q[i].val));
                if(minflow!=0){
                    cost+=q[i].cost*minflow;
                    q[i].val-=minflow;
                    q[i^1].val+=minflow;
                    used+=minflow;
                }
                //可以到达t,加费用,扣流量
                if(used==flow)break;
            }
        }
        return used;
    }
    ll mincostmaxflow(){
        while(spfa()){
            vis[ep]=1;
            while(vis[ep]){
                memset(vis,0,sizeof(vis));
                dfs(sp,inf);
            }
        }
        return maxflow;
    }
    int main()
    {
        int n,p,m,f,N,s;
        scanf("%d",&n);
        sp=0,ep=2*n+1;
        init();
        for(int i=1;i<=n;i++){
            int num;
            scanf("%d",&num);
            add_edge(sp,i+n,num,0);
            add_edge(i,ep,num,0);
        }
        scanf("%d%d%d%d%d",&p,&m,&f,&N,&s);
        for(int i=1;i<=n;i++){
            if(i+1<=n) add_edge(i+n,i+n+1,inf,0);
            if(i+m<=n) add_edge(i+n,i+m,inf,f);
            if(i+N<=n) add_edge(i+n,i+N,inf,s);
            add_edge(sp,i,inf,p);
        }
        mincostmaxflow();
        printf("%lld
    ",cost);
        return 0;
    }
  • 相关阅读:
    (五)Spring Cloud教程——Config(F版本)
    (四)Spring Cloud教程——Zuul(F版本)
    (三)Spring Cloud教程——Hystrix(F版本)
    (二)Spring Cloud教程——Ribbon 和 Feign(F版本)
    (一)Spring Cloud教程——Eureka(F版本)
    3年的坚持,最终造就著作——《Learninghard C#学习笔记》
    WPF快速入门系列(9)——WPF任务管理工具实现
    WPF快速入门系列(8)——MVVM快速入门
    [WPF实用技巧]如何使WPF的TreeView节点之间有连线
    WPF快速入门系列(7)——深入解析WPF模板
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007131.html
Copyright © 2011-2022 走看看