zoukankan      html  css  js  c++  java
  • P1251餐厅计划问题(最小费用最大流)

    题目描述

    一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nn 天(n>mn>m),其费用为 ss 分(s<fs<f)。

    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

    试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

    输入格式

    由标准输入提供输入数据。文件第 1 行有 1 个正整数 NN,代表要安排餐巾使用计划的天数。

    接下来的一行是餐厅在相继的 NN 天里,每天需用的餐巾数。

    最后一行包含5个正整数p,m,f,n,sp,m,f,n,s。pp 是每块新餐巾的费用; mm 是快洗部洗一块餐巾需用天数; ff 是快洗部洗一块餐巾需要的费用; nn 是慢洗部洗一块餐巾需用天数; ss 是慢洗部洗一块餐巾需要的费用。

    输出格式

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

    题解:

    /*
     * P1251餐巾计划问题
     * 题意:
     * 一个餐厅在相继的n天里,每天需用的餐巾数不同。
     * 假设第i天需要ri块餐巾。
     * 餐厅可以购买新的餐巾,每块餐巾的费用为p分。
     * 或者把旧餐巾送到快洗部,洗一块需要m天,其费用为f分。
     * 或者送到慢洗部,洗一块需要n天,其费用为s分。
     * 每次结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块脏的餐巾送到慢洗部,以及多少块保存起来延期送洗,
     * 但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
     * 输出在N天里使用餐巾的最小总花费。
     * 题解:
     * 最小费用最大流。
     * 首先,拆点,把每天拆成早上和晚上。每天晚上会受到脏餐巾,每天早上又有干净的餐巾。
     * 1.从源点向每天晚上连一条流量为当天所用餐巾x,费用为0的边,表示每天晚上从起点获得x条脏餐巾。
     * 2.从每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边,每天白天,表示从汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用。
     * 3.每一天晚上向第二天晚上连一条流量为inf,费用为0的边,表示每天晚上可以将脏餐巾留到第二天晚上。
     * 4.每一天晚上向这一天+快洗所用天数那一天早上连一条流量为inf,费用为快洗所用钱数的边,表示每天晚上可以送去快洗部,在第i+t1天早上收到餐巾。
     * 5.同理,每一天晚上向这一天+慢洗所用天数的那一天早上连一条流量为inf,费用为慢洗所用钱数的边,表示每天晚上可以送去慢洗部,在第i+t2天早上收到餐巾。
     * 6.从起点向每天早上连一条流量为inf,费用为购买餐巾所用钱数的边,表示每天早上可以购买餐巾。
     */
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+100;
    const ll inf=1e18;
    int head[maxn];
    int tot;
    int s,t;
    ll dis[maxn];
    int pre[maxn];
    int lst[maxn];
    ll flow[maxn];
    int visit[maxn];
    ll maxflow;
    ll mincost;
    struct node {
        int u,v;
        ll dis,flow;
        int nxt;
    }edge[maxn];
    void addedge (int u,int v,ll flow,ll dis) {
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].flow=flow;
        edge[tot].dis=dis;
        edge[tot].nxt=head[u];
        head[u]=tot++;
    }
    bool spfa (int s,int t) {
        for (int i=0;i<maxn;i++) dis[i]=inf,flow[i]=inf,visit[i]=0;
        queue<int> q;
        q.push(s);
        visit[s]=1;
        dis[s]=0;
        pre[t]=-1;
        while (!q.empty()) {
            int u=q.front();
            q.pop();
            visit[u]=0;
            for (int i=head[u];i!=-1;i=edge[i].nxt) {
                if (edge[i].flow>0&&dis[edge[i].v]>dis[u]+edge[i].dis) {
                    dis[edge[i].v]=dis[u]+edge[i].dis;
                    pre[edge[i].v]=u;
                    lst[edge[i].v]=i;
                    flow[edge[i].v]=min(flow[u],edge[i].flow);
                    if (!visit[edge[i].v]) {
                        visit[edge[i].v]=1;
                        q.push(edge[i].v);
                    }
                }
            }
        }
        return pre[t]!=-1;
    } 
    void MCMF () {
        while (spfa(s,t)) {
            int u=t;
            maxflow+=flow[t];
            mincost+=flow[t]*dis[t];
            while (u!=s) {
                edge[lst[u]].flow-=flow[t];
                edge[lst[u]^1].flow+=flow[t];
                u=pre[u];
            }
        }
    } 
    int a[maxn];
    int main () {
        memset(head,-1,sizeof(head));
        int n;
        int p,m,f,_n,_s;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        scanf("%d%d%d%d%d",&p,&m,&f,&_n,&_s);
        //1-2*n代表每天的早上和晚上
        s=0,t=2*n+1;
        for (int i=1;i<=n;i++) {
            addedge(s,i+n,a[i],0);
            addedge(i+n,s,0,0);
        }
        for (int i=1;i<=n;i++) {
            addedge(i,t,a[i],0);
            addedge(t,i,0,0);
        }
        for (int i=1;i<n;i++) {
            addedge(i+n,i+n+1,inf,0);
            addedge(i+n+1,i+n,0,0);
        }
        for (int i=1;i<=n;i++) {
            if (i+m>n) continue;
            addedge(i+n,i+m,inf,f);
            addedge(i+m,i+n,0,-f);
        }
        for (int i=1;i<=n;i++) {
            if (i+_n>n) continue;
            addedge(i+n,i+_n,inf,_s);
            addedge(i+_n,i+n,0,-_s);
        }
        for (int i=1;i<=n;i++) {
            addedge(s,i,inf,p);
            addedge(i,s,0,-p);
        }
        MCMF();
        printf("%lld
    ",mincost);
    }
  • 相关阅读:
    HDU 1180 诡异的楼梯 (搜索)
    HDU 1238 Substrings (水)
    HDU 1075 What Are You Talking About (Trie树)
    设计模式(2)-单例模式
    设计模式(1)
    查找搜狐文章里面插入的腾讯视频
    下载喜马拉雅FM的音频
    未格式化的硬盘识别失败
    培训班的好处
    下载新浪博客里的音乐
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13322577.html
Copyright © 2011-2022 走看看