Luogu P1156 垃圾陷阱
题面
垃圾陷阱
题目描述
卡门――农夫约翰极其珍视的一条 Holsteins
奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方,它的深度为
D
D
D(
2
≤
D
≤
100
2 \le D \le 100
2≤D≤100)英尺。
卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。
每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。
假设卡门预先知道了每个垃圾扔下的时间 t t t( 1 ≤ t ≤ 1000 1 \le t \le 1000 1≤t≤1000),以及每个垃圾堆放的高度 h h h( 1 ≤ h ≤ 25 1 \le h \le 25 1≤h≤25)和吃进该垃圾能增加维持生命的时间 f f f( 1 ≤ f ≤ 30 1 \le f \le 30 1≤f≤30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续 10 10 10 小时的能量,如果卡门 10 10 10 小时内(不含 10 10 10 小时,维持生命的时间同)没有进食,卡门就将饿死。特别地,若体力值为 0 0 0 时吃下垃圾或逃出井外也不会饿死。
输入格式
第一行为两个整数, D D D 和 G G G( 1 ≤ G ≤ 100 1 \le G \le 100 1≤G≤100), G G G 为被投入井的垃圾的数量。
第二到第 G + 1 G+1 G+1 行每行包括三个整数: T T T( 1 ≤ T ≤ 1000 1 \le T \le 1000 1≤T≤1000),表示垃圾被投进井中的时间; F F F( 1 ≤ F ≤ 30 1 \le F \le 30 1≤F≤30),表示该垃圾能维持卡门生命的时间;和 H H H( 1 ≤ H ≤ 25 1 \le H \le 25 1≤H≤25),该垃圾能垫高的高度。
输出格式
如果卡门可以爬出陷阱,输出一个整数,表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。
样例 #1
样例输入 #1
20 4
5 4 9
9 3 2
12 6 10
13 1 1
样例输出 #1
13
提示
【样例说明】
卡门堆放她收到的第一个垃圾: h e i g h t = 9 \mathrm{height}=9 height=9;
卡门吃掉她收到的第 2 2 2 个垃圾,使她的生命从 10 10 10 小时延伸到 13 13 13 小时;
卡门堆放第 3 3 3 个垃圾, h e i g h t = 19 \mathrm{height}=19 height=19;
卡门堆放第 4 4 4 个垃圾, h e i g h t = 20 \mathrm{height}=20 height=20。
题解
每个物品(rubbish)有两个处理方式:吃/堆放
先划分维度:时间,高度,血量
时间:每个物品做出选择不消耗时间,在拿到物品时立刻做出选择符合最优化。
剩下两个维度 高度和血量
设计状态
f
[
i
]
[
j
]
:
第
i
个物品堆放到
j
高度的最大血量
f[i][j]:第i个物品堆放到j高度的最大血量
f[i][j]:第i个物品堆放到j高度的最大血量
状态转移方程
对第i个物品:
高度
h
[
i
]
,
能量
E
[
i
]
高度h[i],能量E[i]
高度h[i],能量E[i]
可以得到:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
]
,
f
[
i
−
1
]
[
j
]
+
E
[
i
]
)
f[i][j] = max(f[i][j],f[i - 1][j] + E[i])
f[i][j]=max(f[i][j],f[i−1][j]+E[i])
f [ i ] [ j + h [ i ] ] = m a x ( f [ i ] [ j + h [ i ] ] , f [ i − 1 ] [ j ] ) f[i][j + h[i]] = max(f[i][j + h[i]],f[i - 1][j]) f[i][j+h[i]]=max(f[i][j+h[i]],f[i−1][j])
关于遍历的顺序和条件
-
一层按照时间顺序i in range (1,g)
-
二层从0高度开始 j in range(0,d)
然后关于能否存活的判断,与其用剩余能量>=0的形式不如换成
∑
E
>
=
t
i
\sum E >= t_i
∑E>=ti
在上述条件成立的条件下可以判断
j
+
h
i
>
=
d
j + h_i >= d
j+hi>=d
即有ans = t[i].
核心转移代码:
for(int i = 1;i <= g;i ++){
for(int j = 0;j <= d;j ++){
if(f[i - 1][j] >= r[i].t) {
if(j + r[i].h >= d){
cout << r[i].t;
exit(0);
}
f[i][j] = max(f[i][j],f[i - 1][j] + r[i].f);
f[i][j + r[i].h] = max(f[i][j + r[i].h],f[i - 1][j]);
}
}
if(ans < r[i].t) break;
ans += r[i].f;
}
贴AC代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 105
using namespace std;
struct R{
int t,h,f; //h:高度 f:生命值
bool operator < (const R &x) const{
return t < x.t;
}
}r[MAXN];
int f[MAXN][201];
int main(){
std::ios::sync_with_stdio(false);
int d,g;
cin >> d >> g;
for(int i = 1;i <= g;i ++)
cin >> r[i].t >> r[i].f >> r[i].h;
sort(r + 1,r + g + 1);
f[0][0] = 10;
int ans = 10;
for(int i = 1;i <= g;i ++){
for(int j = 0;j <= d;j ++){
if(f[i - 1][j] >= r[i].t) {
if(j + r[i].h >= d){
cout << r[i].t;
exit(0);
}
f[i][j] = max(f[i][j],f[i - 1][j] + r[i].f);
f[i][j + r[i].h] = max(f[i][j + r[i].h],f[i - 1][j]);
}
}
if(ans < r[i].t) break;
ans += r[i].f;
}
cout << ans;
}