P1156 [USACO01OPEN] 垃圾陷阱

P1156 USACO01OPEN 垃圾陷阱

题目描述

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

卡门想把垃圾堆起来,等到堆得与井深同样高或比井深更高(即,垃圾高度总和 ≥D\geq D≥D)时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

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

假设卡门预先知道了每个垃圾扔下的时间 ttt(1≤t≤10001 \le t \le 10001≤t≤1000),以及每个垃圾堆放的高度 hhh(1≤h≤251 \le h \le 251≤h≤25)和吃进该垃圾能增加维持生命的时间 fff(1≤f≤301 \le f \le 301≤f≤30),要求出卡门最早能逃出井外的时间,已知卡门当前体内有足够持续 101010 小时的能量,如果卡门 101010 小时内(不含 101010 小时,维持生命的时间同)没有进食,卡门就将饿死。特别地,若体力值为 000 时吃下垃圾或逃出井外也不会饿死。

输入格式

第一行为两个整数,DDD 和 GGG(1≤G≤1001 \le G \le 1001≤G≤100),GGG 为被投入井的垃圾的数量。

第二到第 G+1G+1G+1 行每行包括三个整数:ttt(1≤t≤10001 \le t \le 10001≤t≤1000),表示垃圾被投进井中的时间;fff(1≤f≤301 \le f \le 301≤f≤30),表示该垃圾能维持卡门生命的时间;和 hhh(1≤h≤251 \le h \le 251≤h≤25),该垃圾能垫高的高度。

输出格式

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

输入输出样例 #1

输入 #1

复制代码
20 4
5 4 9
9 3 2
12 6 10
13 1 1

输出 #1

复制代码
13

说明/提示

【样例说明】

卡门堆放她收到的第一个垃圾:height=9\mathrm{height}=9height=9;

卡门吃掉她收到的第 222 个垃圾,使她的生命从 101010 小时延伸到 131313 小时;

卡门堆放第 333 个垃圾,height=19\mathrm{height}=19height=19;

卡门堆放第 444 个垃圾,height=20\mathrm{height}=20height=20。

解答

显然,这种题目是 DP\mathrm{DP}DP 题.

状态定义

我们设 dpi,jdp_{i,j}dpi,j 表示处理(吃或者堆起来) 111 ~ iii 的垃圾,当前奶牛维持生命的时间为 jjj 所可以攀爬的最大高度

答案

显然判断是否可以出井的条件就是 dpG,...dp_{G,...}dpG,... 的最大值,形式化的讲,就是

ans=max⁡i=1r(dpG,i) \mathrm{ans}=\max_{i=1}^{r}\big(dp_{G,i}\big) ans=i=1maxr(dpG,i)

其中 rrr 就是奶牛的生命值可能的最大值,也就是 r=G×max⁡f+10r=G\times \max f+10r=G×maxf+10 最大为 r=100×30+10=3010r=100\times 30+10=3010r=100×30+10=3010.

方程

很简单,每个垃圾有两种选择.

  • 吃下去,回复体力值
  • 堆起来

使用刷表法, 方程为:

{dpi+1,j−wait+eat=max⁡(dpi+1,j−wait+eat,dpi,j)(j>wait)dpi+1,j=max⁡(dpi+1,j,dpi,j+height)(j>wait) \begin{cases} dp_{i + 1, j-\mathrm{wait}+\mathrm{eat}}=\max\Big(dp_{i + 1, j-\mathrm{wait}+\mathrm{eat}},dp_{i,j}\Big) \Big(j>\mathrm{wait}\Big) \\ dp_{i+1,j}=\max\Big(dp_{i+1, j}, dp_{i,j}+\mathrm{height}\Big) \Big(j>\mathrm{wait }\Big) \end{cases} ⎩ ⎨ ⎧dpi+1,j−wait+eat=max(dpi+1,j−wait+eat,dpi,j)(j>wait)dpi+1,j=max(dpi+1,j,dpi,j+height)(j>wait)

其中

{wait=两个垃圾等待的时间eat=吃掉当前垃圾回复的体力时间height=垃圾堆放的高度 \begin{cases} \mathrm{wait}=\text{两个垃圾等待的时间} \\ \mathrm{eat}=\text{吃掉当前垃圾回复的体力时间} \\ \mathrm{height}=垃圾堆放的高度 \end{cases} ⎩ ⎨ ⎧wait=两个垃圾等待的时间eat=吃掉当前垃圾回复的体力时间height=垃圾堆放的高度

贪心法输出答案即可

cpp 复制代码
#include <stdio.h>
#include <algorithm>
#include <string.h>

int D, G;
int _max(int x, int y) {return (x > y) ? x : y;}
void max(int& x, int y) {x = _max(x, y);}

struct Trash_t {
	int Fresh_Time;		// 刷新时间
	int Give_Time;		// 提供的时间
	int Height;			// 高度
	
	bool operator < (const Trash_t& other) {
		return Fresh_Time < other.Fresh_Time;			// 按照刷新时间排序
	}
}trash[128];

int dp[128][3510];



int main()
{
	scanf("%d%d", &D, &G);
	
	for (int i = 1; i <= G; i++) scanf("%d%d%d", &trash[i].Fresh_Time, &trash[i].Give_Time, &trash[i].Height);
	
	// 按照刷新时间排序
	std::sort(trash + 1, trash + 1 + G);
	memset(dp, -1, sizeof(dp));
	
	dp[0][10] = 0;
	for (int i = 0; i < G; i++) {
		for (int j = 0; j <= 3500; j++) {
			if (dp[i][j] == -1) continue;
			// 从垃圾 i 等待下一个垃圾的时间
			int wait_time = trash[i + 1].Fresh_Time - trash[i].Fresh_Time;
			if (j < wait_time) continue;
			
			// 吃掉垃圾
			max(dp[i + 1][j - wait_time + trash[i + 1].Give_Time], dp[i][j]);
			// 堆垃圾
			max(dp[i + 1][j - wait_time], dp[i][j] + trash[i + 1].Height);
		}
	}
	
	int ans = 0;
	for (int i = 0; i <= 3500; i++) {
		max(ans, dp[G][i]);
	}
	
//	printf("ans=%d\n", ans);
	if (ans >= D) {
		// 成功
		// 找出最短的时间
		// 显然, 最短的时间就是某一个垃圾的投放时间
		for (int i = 1; i <= G; i++) {
			for (int j = 0; j <= 3500; j++) {
				if (dp[i][j] >= D) {
					// 直接输出垃圾 i 的投放时间
					printf("%d\n", trash[i].Fresh_Time);
					return 0;
				}
			}
		}
	}
	else {
//		printf("QWQ\n");
		// 失败
		// 最多可以活多久, 自然是吃掉所有的垃圾
		// 模拟计算即可
		int time = 10;
		for (int i = 1; i <= G; i++) {
			int wait_time = trash[i].Fresh_Time - trash[i - 1].Fresh_Time;
			if (wait_time > time) {
				printf("%d\n", time + trash[i - 1].Fresh_Time);
				return 0;
			}
			time -= wait_time;
			time += trash[i].Give_Time;
		}
		printf("%d", time + trash[G].Fresh_Time);
	}
	return 0;
}
相关推荐
find1star6 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
迅翼SwiftWing7 小时前
编队系列(总)|固定翼编队如何实现稳定飞行?通信架构、协同算法与工程约束深度解析
算法·架构
LB21127 小时前
力扣160 21 86
算法·leetcode·职场和发展
小智老师PMP8 小时前
2026深度解析|PMP第八版与NPDP核心侧重点本质区别(管理类证书怎么选)
开发语言·分布式·算法·职场和发展·产品经理
HugoStudio_SWAN8 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
a187927218318 小时前
【算法】动态规划第二篇:双序列 DP 三课——继承、计步与断链
算法·leetcode·动态规划·dp·回溯·暴力·算法讲解
江畔柳前堤9 小时前
前台·中台·后台:2026年AI原生时代的架构全景图
开发语言·人工智能·算法·机器学习·架构·scala·ai-native
文心快码BaiduComate10 小时前
2026 OPC x AI Coding 趋势案例交流会圆满落幕:一个人就一支研发团队
算法
ACM-moran10 小时前
条件显化(二分单峰函数+构造数列)
算法·推公式·整数三分
闻缺陷则喜何志丹10 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统