一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri 块餐巾(i = 1, 2, ..., N)。
餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s 分(s<f)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。
但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
S o l u t i o n \mathfrak{Solution} Solution
费用流 + 拆点
此题的建图可以说是非常新奇了。
已知:每天早上要用或收到新的餐巾,晚上要处理脏餐巾。明显每天的早上和晚上操作不同,所以要将每天拆成两个点,早上和晚上。
- 让源点连向晚上,收到待处理脏餐巾,流量为当天使用餐巾数,费用为 0。
- 让早上连向汇点,提供当前所需净餐巾,流量为当天使用餐巾数,费用为 0。显然,当这条路流量满时,代表当天所需餐巾量已达到。
这样连接,保证了网络的联通性,同时可以在此基础上使用费用流解决此问题。
然后再来看其余四种操作:
- 快洗:因为是晚上送去白天收到使用,所以自当天晚上连向 m m m 天后的早上, 费用为 f f f,流量为 i n f inf inf。
- 慢洗:同理。
- 残留餐巾:从今天晚上留到明天晚上,所以自当天晚上连向明天晚上,费用为 0,流量为 i n f inf inf。
- 购买新餐巾:自源点连向早上,费用为 p p p,流量为 i n f inf inf。
综上,易知当这个网络自源点向汇点连通时,满足每一天早上都有当天所需所有餐巾。所以在此基础上可以去跑费用流了。
C o d e + N o t e s \mathfrak{Code + Notes} Code+Notes
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define inf 2147483647