P1251 餐巾计划问题

\(\color{#0066ff}{题目描述}\)

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

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

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

\(\color{#0066ff}{输入格式}\)

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

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

最后一行包含5个正整数\(p,m,f,n,s\)。\(p\) 是每块新餐巾的费用; \(m\) 是快洗部洗一块餐巾需用天数; \(f\) 是快洗部洗一块餐巾需要的费用; \(n\) 是慢洗部洗一块餐巾需用天数; \(s\) 是慢洗部洗一块餐巾需要的费用。

\(\color{#0066ff}{输出格式}\)

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

\(\color{#0066ff}{输入样例}\)

3
1 7 5
11 2 2 3 1

\(\color{#0066ff}{输出样例}\)

134

\(\color{#0066ff}{数据范围与提示}\)

\(N \leq 2000\)

\(ri \leq 10000000\)

\(p,f,s \leq 10000\)

\(时限4s\)

\(\color{#0066ff}{题解}\)

这是一道费用流

首先,拆点

把每天拆成早上晚上

每天晚上会收到脏餐巾,其中一个来源就是当天用的干净的餐巾

这个来源是固定的,我们通过输入可以得知

所以可以理解为从源点获得

每天早上,我们会获得干净的餐巾,同样,有很多来源

下面开始建图

1、从S向每一天晚上连容量为当天需求,权值为0的边,代表从当天早上获得的脏餐巾

2、从每一天早上向T连一条容量为当天需求,权值为0的边,代表当天要供给这么多餐巾(干净的),流满了就代表当天够用,当然最大流一定会让它流满

3、每天晚上向第二天晚上连一条容量为inf,权值为0的边,代表将本日的脏餐巾留到第二天(不能是早上,因为早上只能用干净的餐巾)

4、每天晚上向当天+慢洗店所用天数(注意边界)的那天早上,连容量为inf,边权为慢洗店单价的边,表示当天送一些脏餐巾到慢洗店,在洗完后回到那天早上(变干净了)

5、同上

6、从起点向每天早上连容量为inf,边权为餐巾单价的边,代表可以买新餐巾

一边mcmf就行了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define _ 0
#define LL long long
inline LL in()
{
    LL x=0,f=1; char ch;
    while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*f;
}
struct node
{
    int to;
    LL can,dis;
    node *nxt,*rev;
    node(int to=0,LL can=0,LL dis=0,node *nxt=NULL):to(to),can(can),dis(dis),nxt(nxt){}
    void *operator new (size_t)
    {
        static node *S=NULL,*T=NULL;
        return (S==T&&(T=(S=new node[1024])+1024)),S++;
    }
};
const LL inf=999999999999999LL;
typedef node* nod;
nod head[50505],road[50505];
LL dis[50505],change[50505];
bool vis[50505];
LL need[50505];
LL aa,bb,cc,dd,ee;
int n,s,t;
std::queue<int> q;
inline void add(int from,int to,LL dis,LL can)
{
    nod o=new node(to,can,dis,head[from]);
    head[from]=o;
}
inline void link(int from,int to,LL dis,LL can)
{
    add(from,to,dis,can);
    add(to,from,-dis,0);
    head[from]->rev=head[to];
    head[to]->rev=head[from];
}
inline bool spfa()
{
    for(int i=s;i<=t;i++) dis[i]=change[i]=inf,vis[i]=0;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int tp=q.front(); q.pop();
        vis[tp]=false;
        for(nod i=head[tp];i;i=i->nxt)
        {
            if(dis[i->to]>dis[tp]+i->dis&&i->can>0)
            {
                dis[i->to]=dis[tp]+i->dis;
                road[i->to]=i;
                change[i->to]=std::min(change[tp],i->can);
                if(!vis[i->to]) vis[i->to]=true,q.push(i->to);
            }
        }
    }
    return change[t]!=inf;
}
inline void mcmf()
{
    LL cost=0;
    while(spfa())
    {
        cost+=change[t]*dis[t];
        for(int i=t;i!=s;i=road[i]->rev->to)
        {
            road[i]->can-=change[t];
            road[i]->rev->can+=change[t];
        }
    }
    printf("%lld",cost);
}
int main()
{
    n=in();
    s=0,t=(n<<1)+1;
    for(int i=1;i<=n;i++) need[i]=in();
    aa=in(),bb=in(),cc=in(),dd=in(),ee=in();
    for(int i=1;i<=n;i++)
    {
        link(s,i+n,aa,inf);
        link(s,i,0,need[i]);
        link(i+n,t,0,need[i]);
        if(i!=n) link(i,i+1,0,inf);
        if(i+bb<=n) link(i,i+n+bb,cc,inf);
        if(i+dd<=n) link(i,i+n+dd,ee,inf);
    }
    mcmf();
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10114958.html

时间: 2024-10-12 00:20:31

P1251 餐巾计划问题的相关文章

P1251 餐巾计划 (网络流)

题意:餐厅每天会需要用Ri块新的餐巾 用完后也会产生Ri块旧的餐巾 每天购买新的餐巾单价p元 每天产出的旧餐巾可以送到快洗部花费每张c1元 在i + v1天可以使用 也可以花费c2元每张送到慢洗部 在i + v2天可以使用 问n天的最小花费 题解:把每天拆点 分为用出去的 和得到的旧餐巾 s -> 用出去的  表示每天可以买新的 用出去的-> t 表示每天一定会用Ri张纸巾 s-> 旧 表示每天一定会产生Ri块旧的纸巾 特判一下后 旧的按题意可以送去快洗和慢洗 然后今天没用完的旧的 明天

P1251 餐巾计划问题 (费用流)

题目链接 方法: 重点在建图!!!将一天拆成晚上和早上: 1. 从源点向每一天晚上连一条流量为当天所用餐巾x,费用为0的边: 2. 每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边: 3. 从每一天晚上向第二天晚上连一条流量为INF,费用为0的边,表示每天晚上可以将脏餐巾留到第二天晚上: 4. 从每一天晚上向这一天+快洗所用天数t1的那一天早上连一条流量为INF,费用为快洗所用钱数的边,表示每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 : 5. 从每一天晚上向这一天+慢洗所用天数t

餐巾计划问题

餐巾计划问题 Time Limit: 1000 MS  Memory Limit: 65536 KB Description 一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同.假设第i天需要ri块餐巾(i=1, 2,-,N).餐厅可以购买新的餐巾,每块餐巾的费用为p分:或者把旧餐巾送到快洗部, 洗一块需m天,其费用为f 分:或者送到慢洗部,洗一块需n 天(n>m),其费用为s< f 分. 每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多 少块保存起来延期送洗.

AC日记——餐巾计划问题 洛谷 P1084

餐巾计划问题 思路: 氧气优化水过: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 4005 #define maxque 1000005 #define INF 0x7fffffff #define ll long long ll n,head[maxn],E[maxque],V[maxque],W[maxque],F[maxque]; ll pi,qt,qc,st,sc,s,t,cnt=1,day[maxn],

线性规划与网络流10 餐巾计划问题

算法实现题 8-10 餐巾计划问题(习题 8-21)?问题描述:一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同.假设第 i 天需要 ri块餐巾(i=1,2,…,N).餐厅可以购买新的餐巾,每块餐巾的费用为 p 分:或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分:或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分.每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗.但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天

【网络流24题】餐巾计划(图解)

LOJ 6008[网络流24题]餐巾计划 题解 一张图片说明建图方法: 解说: 这种建图方法完美区分开了"脏餐巾"和"干净餐巾"两种餐巾. 每天一定会有r[i]个脏餐巾,所以源点向每天的"脏餐巾"(图上used)连边,容量r[i],费用是0.另外,前一天的脏餐巾也可以留到下一天再处理,所以每天的used点向下一天的used点连一条边,容量INF,费用是0. 每天会需要r[i]个干净餐巾,所以每天的"干净餐巾"向汇点连边(图上n

【网络流24题】餐巾计划问题(最小费用最大流)

[网络流24题]餐巾计划问题(最小费用最大流) 题面 COGS 洛谷上的数据范围更大,而且要开longlong 题解 餐巾的来源分为两种: ①新买的 ②旧的拿去洗 所以,两种情况分别建图 先考虑第一种 因为新买餐巾没有任何限制,并且随时可以买 所以直接从源点向每一天连边,容量为INF,费用为餐巾的价格 因为流要流出去,所以每个点向汇点连边,容量为每天的用量,费用为0 第二种,旧的拿去洗 首先考虑一下怎么算有多少旧的餐巾 每天用旧的餐巾的数量值一定的,不可能变多 因此从源点向这些点连边,容量为每天

LOJ #6008. 「网络流 24 题」餐巾计划

#6008. 「网络流 24 题」餐巾计划 题目描述 一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同.假设第 i ii 天需要 ri r_ir?i?? 块餐巾.餐厅可以购买新的餐巾,每块餐巾的费用为 P PP 分:或者把旧餐巾送到快洗部,洗一块需 M MM天,其费用为 F FF 分:或者送到慢洗部,洗一块需 N NN 天,其费用为 S SS 分(S<F S < FS<F). 每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗.

【题解】餐巾计划问题

[题解]餐巾计划问题 orz argent 一定要注意不要调到题目里的坑里来了,要记得脱离实际(大雾). 建模方法:我觉得没什么好讲的,真的是灵感问题,此外,这个问题可以直接无源汇上下界网络流.但是我不会 graph LR 净1 --w=r,c=0--> T 净2 --w=r,c=0--> T 净3 --w=r,c=0--> T 净4 --w=r,c=0--> T S --w=r,c=p--> 净1 S --w=r,c=p--> 净2 S --w=r,c=p-->