题解:P1156 垃圾陷阱
P1156 垃圾陷阱#
思路:#
很显然这是一道动态规划,且每个物品有两种选择:用作增加生命或高度。
增加高度会损失一定的生命,反之同理,是不是很像背包问题?确实是它的变形。
考虑设 \(f[i][j]\) 表示到第 \(i\) 个物品,生命值为 \(j\) 时所到达的最大高度。
那么我们考虑转移,显然对于物品 \(i\) 用作增加高度有:
\(f[i][j]=max(f[i-1][j]+h[i])\)
用作增加生命有:
\(f[i][j]=max(f[i-1][j-f[i]])\)
坑点:#
-
注意转移调用变量时奶牛是否还存活。
-
给出的垃圾掉落时间的 \(t\) 数组不保证单调递增,需要排序。
代码:#
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node {
ll t, f, h, sum;
bool operator < (node &a) {return t<a.t;}
}a[1005];
ll h, n;
ll f[105][100005]; //f[i][j]表示前i个垃圾生命值为j时能达到的最高高度
int main() {
cin >> h >> n;
for(int i=1; i<=n; i++) cin >> a[i].t >> a[i].f >> a[i].h; //t表示投放时间,f表示增加的生命值,h表示垫高高度
sort(a+1, a+n+1); //注意给出的时间不递增
a[0].sum=10;
for(int i=1; i<=n; i++) a[i].sum=a[i-1].sum+a[i].f; //a[i].sum表示到i能达到的最大高度
memset(f, -0x3f, sizeof(f));
f[0][10]=0; //初始化
for(int i=1; i<=n; i++) {
if(a[i].t>a[i-1].sum) { //就算前面的所有垃圾都吃也坚持不到这个垃圾,输出最大高度
cout << a[i-1].sum;
exit(0);
}
for(int j=a[i].t; j<=a[i].sum; j++) { //j从a[i].t开始枚举保证能存活到当前垃圾投放,且最大高度不大于a[i].sum
f[i][j]=max(f[i][j], f[i-1][j]+a[i].h); //这个垃圾用来垫高高度
//接下来考虑这个垃圾用来增加生命值,那么j-a[i].f>=0且j-a[i].f>=a[i].t(保证能活到当前垃圾时间)
if(j-a[i].f>=0&&j-a[i].f>=a[i].t) f[i][j]=max(f[i][j], f[i-1][j-a[i].f]);
if(f[i][j]>=h) { //如果不小于h说明到i时就出去了,输出a[i].t
cout << a[i].t;
exit(0);
}
}
}
cout << a[n].sum; //能运行到这里说明所有最大高度不足以出洞
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现