zoukankan      html  css  js  c++  java
  • 餐巾计划问题

    餐巾计划问题

    Time Limit: 1000 MS  Memory Limit: 65536 KB

    Description

    一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同。假设第i天需要ri块餐巾(i=1, 2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为p分;或者把旧餐巾送到快洗部, 洗一块需m天,其费用为f 分;或者送到慢洗部,洗一块需n 天(n>m),其费用为s< f 分。 每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多 少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。 试设计一个算法为餐厅合理地安排好N 天中餐巾使用计划,使总的花费最小。 编程任务: 编程找出一个最佳餐巾使用计划.
    由文件input.txt提供输入数据。文件第1 行有6 个正整数N,p,m,f,n,s。N 是要安排餐巾 使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗 一块餐巾需要的费用;n是慢洗部洗一块餐巾需用天数;s是慢洗部洗一块餐巾需要的费用。 接下来的N 行是餐厅在相继的N 天里,每天需用的餐巾数。
    程序运行结束时,将餐厅在相继的N 天里使用餐巾的最小总花费输出到文件output.txt 中。
     
    样例输入:
    3 10 2 3 3 2 5 6 7
    样例输出:
    145   
    题解:
    首先看到这道题的时候并没有想到正解,但至少是一个最小费用流。
    一开始的思路是拆点,然后x和y之间连一条流量为a[i]费用为0的边,x分别和y+d1和y+d2建边,源点和汇点分别和x和y建边。WA到不行。
    沉思两天之后终于想到了正解,把天数拆成x和y,y用来表示直接买的餐巾,x用来表示洗完之后的餐巾。因此只需要将x和y+d1和y+d2建边就可以了,当然y和y+1也要建边,因为洗完的餐巾是可以继续传下去的。最后就只要将源点和xy分别建边,汇点和y建边就可以了。
    代码如下:
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    using namespace std;
    int n,m;
    struct node
    {
        int next,to;
        long long cap,cost;
    }edge[400001];
    int sze=1,head[5001];
    long long a[5001];
    void putin(int from,int to,long long cap,long long cost)
    {
        sze++;
        edge[sze].to=to;
        edge[sze].cap=cap;
        edge[sze].cost=cost;
        edge[sze].next=head[from];
        head[from]=sze;
    }
    void in(int from,int to,long long cap,long long cost)
    {
        putin(from,to,cap,cost);
        putin(to,from,0,-cost);
    }
    long long ans,f[5001];
    int pre[5001],vis[5001];
    bool bfs(int src,int des)
    {
        int i;
        for(i=0;i<=n*2+1;i++){f[i]=1e18;vis[i]=0;}
        queue<int>mem;
        mem.push(src);
        f[src]=0;vis[i]=1;
        while(!mem.empty())
        {
            int x=mem.front();mem.pop();
            vis[x]=0;
            for(i=head[x];i!=-1;i=edge[i].next)
            {
                int y=edge[i].to;
                if(edge[i].cap&&f[y]>f[x]+edge[i].cost)
                {
                    f[y]=f[x]+edge[i].cost;
                    pre[y]=i;
                    if(!vis[y]){mem.push(y);vis[y]=1;}
                }
            }
        }
        if(f[des]==1e18)return 0;
        else return 1;
    }
    void change(int src,int des)
    {
        int x=des;
        long long flow=1e18;
        while(x!=src)
        {
            flow=min(flow,edge[pre[x]].cap);
            x=edge[pre[x]^1].to;
        }
        x=des;
        while(x!=src)
        {
            ans+=flow*edge[pre[x]].cost;
            edge[pre[x]].cap-=flow;
            edge[pre[x]^1].cap+=flow;
            x=edge[pre[x]^1].to;
        }
    }
    void mincostflow(int src,int des)
    {
        while(bfs(src,des))change(src,des);
    }
    int main()
    {
        int i,j;
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        long long s,d1,c1,d2,c2;
        scanf("%lld%lld%lld%lld%lld",&s,&d1,&c1,&d2,&c2);
        for(i=1;i<=n;i++)scanf("%lld",&a[i]);
        for(i=1;i<=n;i++)
        {
            if(i>=2)in(i+n-1,i+n,2e8,0);
            in(0,i,a[i],0);
            in(0,n+i,a[i],s);
            if(i+d1<=n)in(i,i+n+d1,a[i],c1);
            if(i+d2<=n)in(i,i+n+d2,a[i],c2);
            in(n+i,n*2+1,a[i],0);
        }
        mincostflow(0,n*2+1);
        cout<<ans;
        return 0;
    }
     
  • 相关阅读:
    Intouch 制作自定义登录弹窗
    ifix vba 读取计算机中的txt文件,截取字符串显示
    intouch 开发源程序加密方法
    语音报警系统说明
    ifix历史数据(H04/H08/H24)转换为CSV文件导出
    ifix 自动化(Automation)错误弹窗的解决方案
    云平台制作(二)-平台展示
    knudson hypothesis 二次突变假说
    纯合子,杂合子,杂合性缺失
    zero-base coordinate 和one-base coordinate
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/6942064.html
Copyright © 2011-2022 走看看