Luogu P1156 垃圾陷阱

Luogu P1156 垃圾陷阱

题面

垃圾陷阱

题目描述

卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方,它的深度为 D D D 2 ≤ D ≤ 100 2 \le D \le 100 2D100)英尺。

卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间 t t t 1 ≤ t ≤ 1000 1 \le t \le 1000 1t1000),以及每个垃圾堆放的高度 h h h 1 ≤ h ≤ 25 1 \le h \le 25 1h25)和吃进该垃圾能增加维持生命的时间 f f f 1 ≤ f ≤ 30 1 \le f \le 30 1f30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续 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 1G100), G G G 为被投入井的垃圾的数量。

第二到第 G + 1 G+1 G+1 行每行包括三个整数: T T T 1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000),表示垃圾被投进井中的时间; F F F 1 ≤ F ≤ 30 1 \le F \le 30 1F30),表示该垃圾能维持卡门生命的时间;和 H H H 1 ≤ H ≤ 25 1 \le H \le 25 1H25),该垃圾能垫高的高度。

输出格式

如果卡门可以爬出陷阱,输出一个整数,表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。

样例 #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[i1][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[i1][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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值