• 「网络流24题」餐巾计划问题


    题目描述 Description

    一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分。
    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
    试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。
    编程找出一个最佳餐巾使用计划.

    输入描述 Input Description

    第 1 行有 6 个正整数 N,p,m,f,n,s。N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n 是慢洗部洗一块餐巾需用天数;s 是慢洗部洗一块餐巾需要的费用。接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数。

    输出描述 Output Description

    将餐厅在相继的 N 天里使用餐巾的最小总花费输出

    样例输入 Sample Input

    3 10 2 3 3 2

    5

    6

    7

    样例输出 Sample Output

    145 

    题目分析

    【问题分析】

    网络优化问题,用最小费用最大流解决。

    【建模方法】

      把每天分为二分图两个集合中的顶点Xi,Yi,建立附加源S汇T。

      题目所说的每天需用ri块餐巾,我们可以这么理解,把一天拆成两个点Xi和Yi(上午和下午),一天既然需要用ri块餐巾,则必定会消耗ri块,所以我们把Xi表示为这一天接收到的干净的餐巾数,Yi表示为今天要清洗的餐巾数,那么就好建边了.

      从Xi-->X(i+1)建一条(inf,0)的边,表示此边容量无穷大,费用为0,理解为前一天可以把没用完的餐巾留到后一天

      从源点S-->每个Xi建一条(inf,p)的边,表示无论如何你至少可以通过买餐巾来达到需求

      从源点S-->每个Yi建一条(ri,0)的边

      从每个Xi-->汇点T点建一条(ri,0)的边

      从每个Yi-->X(i+m)建一条(inf,f)的边表示每天可以送餐巾到快洗部,费用为f

      同理从每个Yi-->X(i+n)建一条(inf,s)的边表示每天可以送餐巾到慢洗部,费用为s

    求网络最小费用最大流,费用流值就是要求的最小总花费。

    【建模分析】

      这个问题的主要约束条件是每天的餐巾够用,而餐巾的来源可能是最新购买,也可能是前几天送洗,今天刚刚洗好的餐巾。每天用完的餐巾可以选择送到快洗部或慢洗部,或者留到下一天再处理。

      在网络上求出的最小费用最大流,满足了问题的约束条件(因为在这个图上最大流一定可以使与T连接的边全部满流,其他边只要有可行流就满足条件),而且还可以保证总费用最小,就是我们的优化目标。

      然后直接跑费用流模板

      上代码

      

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<queue>
    #define in(i) (i=read())
    #define inf (2147483647)
    using namespace std;
    typedef long long lol;//就是要注意一点因为最大值赋的是int类型最大值,所以有乘法运算就会爆int,so开long long
    lol read()
    {
        lol ans=0,f=1;
        char i=getchar();
        while(i<'0'||i>'9')
        {
            if(i=='-') f=-1;
            i=getchar();
        }
        while(i>='0'&&i<='9')
        {
            ans=(ans<<3)+(ans<<1)+i-'0';
            i=getchar();
        }
        return ans*f;
    }
    struct edge
    {
        lol to,next,cap,v;
    }e[40010];
    lol head[40010];
    lol lev[4010],vis[4010];
    lol len=1;
    void add(lol a,lol b,lol c,lol d)
    {
        e[++len].to=b;
        e[len].next=head[a];
        e[len].cap=c;
        e[len].v=d;
        head[a]=len;
    }
    lol pre[3010];
    bool bfs(lol s,lol t)
    {
        queue<lol>q;
        memset(lev,127/3,sizeof(lev));
        q.push(s);
        lev[s]=0;
        while(!q.empty())
        {
            lol x=q.front();
            q.pop();
            for(lol i=head[x];i;i=e[i].next)
            {
                lol to=e[i].to;
                if(e[i].cap>0&&lev[to]>lev[x]+e[i].v)
                {
                    lev[to]=lev[x]+e[i].v;
                    pre[to]=i;
                    q.push(to);
                }
            }
        }
        if(lev[t]<lev[0]) return 1;
        return 0;
    }
    lol change(lol s,lol t)
    {
        lol x=t,flow=inf,ans=0;
        while(x!=s)
        {
            flow=min(flow,e[pre[x]].cap);
            x=e[pre[x]^1].to;
        }
        x=t;
        while(x!=s)
        {
            e[pre[x]].cap-=flow;
            e[pre[x]^1].cap+=flow;
            ans+=flow*e[pre[x]].v;
            x=e[pre[x]^1].to;
        }
        return ans;
    }
    int main()
    {
        lol tot=0;
        lol n,r;
        lol p,a,f,b,s;
        in(n);
        for(lol i=1;i<=n;i++)
        {
            in(r);
            add(i,(n<<1)+2,r,0);//Xi-->T
            add((n<<1)+2,i,0,0);
            add((n<<1)+1,i+n,r,0);//S-->Yi
            add(i+n,(n<<1)+1,0,0);
        }
        in(p);
        for(lol i=1;i<=n;i++)
        {
            add((n<<1)+1,i,inf,p);//S-->Xi,买餐巾
            add(i,(n<<1)+1,0,-p);
        }
        for(lol i=1;i<n;i++)
        {
            add(i,i+1,inf,0);//前一天留到第二天
            add(i+1,i,0,0);
        }
        in(a);in(f);
        for(lol i=1;i<=n-a;i++)
        {
            add(i+n,i+a,inf,f);//送到快洗部
            add(i+a,i+n,0,-f);
        }
        in(b);in(s);
        for(lol i=1;i<=n-b;i++)
        {
            add(i+n,i+b,inf,s);//送到慢洗部
            add(i+b,i+n,0,-s);
        }
        while(bfs((n<<1)+1,(n<<1)+2))
        {
            tot+=change((n<<1)+1,(n<<1)+2);
        }
        cout<<tot<<endl;
        return 0;
    }
    博主蒟蒻,随意转载.但必须附上原文链接
    http://www.cnblogs.com/real-l/
  • 相关阅读:
    python——实现三级菜单选择的功能(原创)
    Python之路购物车
    Python基础介绍
    python登陆接口编写
    Oculus Store游戏下载默认路径修改方法
    【转载】关于api-ms-win-crt-runtimel1-1-0.dll缺失的解决方案
    安装Appium
    ASP.NET之MVC 微信公众号授权给第三方平台的技术实现流程一(获取第三方平台access_token)
    C# 利用反射更改父类公开对象
    mysql 根据某个值叠加查询
  • 原文地址:https://www.cnblogs.com/real-l/p/8412951.html
Copyright © 2020-2023  润新知