P1156 垃圾陷阱 (动态规划)

https://www.luogu.org/problemnew/show/P1156

题解

这题确定状态很关键,一开始我想的是将时间和生命作为状态,这样需要枚举的便是时间和生命的大小,这些都是不确定的值,而且最大可能到达3000以上,并且一个时间点可能有多个垃圾,每个垃圾又有吃与堆两种选择,遂凉,不可做。但竟然混了82分。

其实这就是一个背包问题,不必要考虑时间轴,生命值其实就相当于时间轴,如果状态中的生命值小于第i个垃圾到第i+1个垃圾所需的生命值,那么这个状态便可舍弃。一个垃圾有高度和生命两个值,可以将状态设置能前i个垃圾堆到高度为h时的最大生命值是多少。这样的话只需枚举垃圾数和高度。要注意的细节便是要先将垃圾按时间从小到大排序,这样才能保证无后效性。当高度为d时且生命值大于等于0,就可以退出了。活不了的情况下可以另行处理,即每次都吃垃圾,吃到不能吃为止。

代码

#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 5000+5;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxn];

struct Trash{
   int t,f,h;
   bool operator < (const Trash& rhs) const {
   	return t < rhs.t;
   }
}a[maxn];
int sum[maxn];
int d,g;

int main() {
   scanf("%d%d", &d, &g);
   int t,f,h;
   for(int i = 1; i <= g; ++i) {
   	scanf("%d%d%d", &a[i].t, &a[i].f, &a[i].h);
   	sum[a[i].t] += a[i].f;
   }
   sort(a+1,a+1+g);
   memset(dp, -INF, sizeof dp);
   dp[0][0] = 10;
   for(int i = 1; i <= g; ++i) {
   	for(int j = d; j >= 0; --j) {
   		if(dp[i-1][j]-(a[i].t-a[i-1].t) < 0) continue;
   		// 吃
   		dp[i][j] = max(dp[i][j], dp[i-1][j]+a[i].f-(a[i].t-a[i-1].t));
   		// 堆
   		dp[i][j+a[i].h] = max(dp[i][j+a[i].h], dp[i-1][j]-(a[i].t-a[i-1].t));
   		if(dp[i][j+a[i].h] >= 0 && j+a[i].h >= d) {
   			cout << a[i].t << endl;
   			exit(0);
   		}
   	}
   }
   int die = 10;
   for(int i = 0; i <= die; ++i) {
   	die += sum[i];
   }
   cout << die << endl;
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值