【费用流】【网络流24题】【P1251】 餐巾计划问题
Description
一个餐厅在相继的 \(N\) 天里,每天需用的餐巾数不尽相同。假设第 \(i\) 天需要 \(r_i\)块餐巾。餐厅可以购买新的餐巾,每块餐巾的费用为 \(p\) 分;或者把旧餐巾送到快洗部,洗一块需 \(m\) 天,其费用为 \(f\) 分;或者送到慢洗部,洗一块需 \(n\) 天(\(n>m\)),其费用为 \(s\) 分(\(s<f\))。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 \(N\) 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
Input
第一行是一个整数 \(N\) 代表天数
下面一行 \(n\) 个数字代表每天的需求
下面一行五个参数分别是 \(p,m,f,n,s\)
Output
一行一个数字代表答案
Hint
\(1~\leq~n~\leq~2000\)
\(1~\leq~r_i~\leq~10^7\)
\(1~\leq~f,p,s~\leq~10000\)
Solution
考虑费用流。
显然需要拆点,把每天拆成上午和晚上。
最初的想法是每天早晨连向晚上来控制当天的需求,然后通过源点连向第一个白天获得新的毛巾,晚上连向白天来洗毛巾,白天到下一天白天,晚上到下一天晚上连边来攒毛巾,最后一天晚上连汇点来。但是事实上由于需要跑满最大流,所以这样的建图方法一定会使得源点流出的流是每天的需求和,从而达到最大流,这样显然不一定是最优的。
考虑这样建图失败的原因是洗毛巾代表的流已经在之前从白天流到黑夜了,为了满足最大流所以这部分一定不能再从白天流向黑夜一次。为了解决这个问题,我们必须让代表洗毛巾的流以前没有从白天到黑夜跑过。于是我们直接从源点连向黑夜,容量为该天的需求,费用为 \(0\),代表该天黑夜获得了当天的脏毛巾。
为了控制满流代表满足需求,我们每天白天连向汇点,容量为当天的需求。剩下的边依然同上,但是去除掉白天之间的边以及白天流向当天晚上的边。
这样我们让代表不同意义的流来源不同,他们对最大流产生的贡献也就相同了,因此可以在这样的基础上最小化费用。
具体的,建图方式为:
从 | 到 | 容量 | 费用 | 意义 |
---|---|---|---|---|
源点 | 每天晚上 | 当天消耗 | 0 | 每天晚上获得当天消耗的脏毛巾 |
每天早上 | 汇点 | 当天消耗 | 0 | 当天消耗的毛巾,满流代表满足消耗 |
每天晚上 | \(m\) 天后的早上 | INF | \(f\) | 快洗 |
每天晚上 | \(n\) 天后的早上 | INF | \(s\) | 慢洗 |
源点 | 每天早上 | INF | \(p\) | 购买新餐巾 |
每天晚上 | 第二天晚上 | INF | \(0\) | 用过的脏餐巾攒下来后面洗 |
另外注意到数据范围需要开 long long
Code
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
typedef long long ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 4010;
const int INF = 0x3f3f3f3f;
struct Edge {
Edge *nxt, *bk;
int from, to, flow, fee;
};
Edge *hd[maxn], *pre[maxn];
inline void cont(Edge *u, Edge *v, int from, int to, int fl, int fe) {
u->from = from; u->to = to; u->flow = fl; u->fee = fe; u->bk = v; u->nxt = hd[from]; hd[from] = u;
}
inline void conet(int from, int to, int fl, int fe) {
Edge *u = new Edge, *v = new Edge;
cont(u, v, from, to, fl, fe); cont(v, u, to, from, 0, -fe);
}
int n, a, b, c, d, f, s, t;
int MU[maxn], night[maxn], cost[maxn], maxflow[maxn];
bool inq[maxn];
std::queue<int>Q;
ll ans;
bool SPFA();
void argu();
int main() {
freopen("1.in", "r", stdin);
qr(n);
for (int i = 1; i <= n; ++i) qr(MU[i]);
qr(a); qr(b); qr(c); qr(d); qr(f);
s = (n << 1) | 1; t = (n << 1) + 2;
for (int i = 1; i <= n; ++i) night[i] = i + n;
for (int i = 1; i <= n; ++i) {
conet(s, night[i], MU[i], 0);
conet(i, t, MU[i], 0);
if ((i + b) <= n) conet(night[i], i + b, INF, c);
if ((i + d) <= n) conet(night[i], i + d, INF, f);
conet(s, i, MU[i], a);
if (i != n) conet(night[i], night[i + 1], INF, 0);
}
while (SPFA()) argu();
qw(ans, '\n', true);
return 0;
}
bool SPFA() {
memset(inq, 0, sizeof inq);
memset(cost, 0x3f, sizeof cost);
memset(maxflow, 0, sizeof maxflow);
maxflow[s] = INF; cost[s] = 0; Q.push(s);
while (!Q.empty()) {
int h = Q.front(); Q.pop(); inq[h] = false; if (!maxflow[h]) continue;
for (Edge *e = hd[h]; e; e = e->nxt) if (e->flow > 0) {
int to = e->to;
if (cost[to] > (cost[h] + e->fee)) {
cost[to] = cost[h] + e->fee;
maxflow[to] = std::min(e->flow, maxflow[h]);
if (!inq[to]) Q.push(to);
inq[to] = true; pre[to] = e;
}
}
}
return cost[t] != INF;
}
void argu() {
for (auto e = pre[t]; e; e = pre[e->from]) {
e->flow -= maxflow[t];
e->bk->flow += maxflow[t];
}
ans += 1ll * maxflow[t] * cost[t];
}
Summary
同样流过一条边的两个流,如果一个已经对最大流产生过贡献另一个没有,那么最大流一定会选择流过没产生贡献的那个流。解决方法是修改另一个流的路径使得他还没产生过贡献。
【费用流】【网络流24题】【P1251】 餐巾计划问题的更多相关文章
- 网络流24题 P1251 餐巾计划问题 拆点
题目描述 一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同.假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N).餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送 ...
- LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图
#6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流)
Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流) Description 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,-,N).餐厅可以从三种途径获得餐巾. ...
- [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划
[luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划 试题描述 一个餐厅在相继的 \(N\) 天里,第 \(i\) 天需要 \(R_i\) 块餐巾 \((i=l,2,-,N)\) ...
- LOJ #6008. 「网络流 24 题」餐巾计划
#6008. 「网络流 24 题」餐巾计划 题目描述 一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同.假设第 i ii 天需要 ri r_iri 块餐巾.餐厅可以购买新的餐巾,每块餐 ...
- 【刷题】LOJ 6008 「网络流 24 题」餐巾计划
题目描述 一个餐厅在相继的 \(n\) 天里,每天需用的餐巾数不尽相同.假设第 \(i\) 天需要 \(r_i\) 块餐巾.餐厅可以购买新的餐巾,每块餐巾的费用为 \(P\) 分:或者把旧餐巾送到快洗 ...
- LibreOJ #6008. 「网络流 24 题」餐巾计划
这道题其实我在刚学 OI 的时候就在一本通上看见过,还记得上面写着"新餐巾一次性买完"之类的话.当时还很稚嫩(现在也是),想了好久,根本想不出来. 学了网络流之后发现这道题的图也是 ...
- LG2770/LOJ6122 航空路线问题 费用流 网络流24题
问题描述 LG2770 LOG6122 题解 教训:关掉流同步之后就不要用其他输入输出方式了. 拆点. 两个拆点之间连\((1,1)\),其他连\((1,0)\) \(\mathrm{Code}\) ...
- Cogs 727. [网络流24题] 太空飞行计划(最大权闭合子图)
[网络流24题] 太空飞行计划 ★★☆ 输入文件:shuttle.in 输出文件:shuttle.out 简单对比 时间限制:1 s 内存限制:128 MB [问题描述] W 教授正在为国家航天中心计 ...
- 初识费用流 模板(spfa+slf优化) 餐巾计划问题
今天学习了最小费用最大流,是网络流算法之一.可以对于一个每条边有一个容量和一个费用(即每单位流的消耗)的图指定一个源点和汇点,求在从源点到汇点的流量最大的前提下的最小费用. 这里讲一种最基础也是最好掌 ...
随机推荐
- Cocos2d-x的跨平台原理
为了充分发挥硬件性能,手机游戏通常使用Native App开发模式,这就造成开发商要为iOS 和Android平台用户开发不同的应用,无论是产品迭代还是运行维护都非常麻烦.Cocos2d-x在iOS, ...
- PHP 伪协议
1.file:// file://用于访问本地文件系统,不受allow_url_fopen影响 <?php include($_GET['file']); ?> 2.http:// GET ...
- node http模块搭建简单的服务和客户端
node-http Node.js提供了http模块,用于搭建HTTP服务端和客户端. 创建Web服务器 server.js /** * node-http 服务端 */ let http = req ...
- The serializable class XXX does not declare a static final serialVersionUID field of type long的警告
原文: http://blog.csdn.net/ultrakang/article/details/41820543
- “Hello World!”团队第七周召开的第六次会议
博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八 .功能说明书 一.会议时间 2017年12月6日 11:20-12:00 二 ...
- 个人作业Week7
1.在做个人项目的时候,由于很久都没有写这么大的程序了,对程序的感觉还没有恢复,因此,没能完全完成个人项目.现在回去看个人项目的代码(针对完成的代码来看),完全就是一个大泥球,代码的结构性太差,基本上 ...
- VirtualBox安装增强功能
一.安装依赖包 #yum install kernel-headers #yum install kernel-devel #yum install gcc* #yum install make 二. ...
- PAT 1001 A+B Fotmat
源码 1001. A+B Format (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Calcula ...
- #1490 : Tree Restoration
微软 2017春招真题 题目 There is a tree of N nodes which are numbered from 1 to N. Unfortunately, its edges a ...
- iOS App之间常用的五种通信方式及适用场景总结
iOS系统是相对封闭的系统,App各自在各自的沙盒(sandbox)中运行,每个App都只能读取iPhone上iOS系统为该应用程序程序创建的文件夹AppData下的内容,不能随意跨越自己的沙盒去访问 ...