洛谷P1156 垃圾陷阱

博客详细解析了洛谷P1156题目的动态规划解决方案。奶牛在井中面对垃圾,需要通过堆砌垃圾延长存活时间或增高逃出。博主阐述了问题的思路、状态定义、转移方程,并提供了代码实现。重点讨论了动态规划的状态设计和转移条件,以及初始化和边界条件的处理。
摘要由CSDN通过智能技术生成
传送门:洛谷P1156 垃圾陷阱
废话

只是单纯想把动态规划前前后后理清楚 其实是防止以后自己看不懂自己的代码,有些地方可能说的有点冗余降低了阅读体验,还请见谅

题目大意

奶牛初始存活时间为10。深度为H的井中隔一段时间会掉下来一个垃圾,一共n个。每个垃圾可以拿来加存活时间或者垫高度,每个垃圾掉下来前的等待会相应减少存活时间。一旦堆出的高度≥H就能跑出去,一旦存活时间<0则死亡。求出最快多久能出去;若活着出不去则求出最长存活时间。

思路

大致方向

一个垃圾只有堆或者吃两种选择
可以想象成一个背包有n个物品可供选择是吃还是堆,那么这道题就是一道类似01背包的动态规划 其实还是道淼题

状态定义

由于有时间这个状态而要求的恰恰就是最短的逃生时间,那么这道题的时间就对应了01背包的价值。考虑将dp值定义为时间
具体怎么定义?这还用问吗
首先以背包的定义方式,第一维是垃圾编号是肯定的 (数据范围这么小就不优化了)
还要一维记录背包容量,第二维就是高度
完整的状态就是dp[i][j]表示前i个垃圾堆的高度为j时奶牛剩余的最大存活时间
为什么时间是最大?求的不是最短时间吗? orz这是什么问题
使用同样前i个垃圾堆相同垃圾高度的情况下,剩余时间更大肯定是更优的
所以dp要不断更新最大值

转移方程

先根据题意初始化 dp[0][0] = 10 (没有垃圾掉下来,堆出的初始高度为0,能活10小时)
转移方程跟01背包别无大异无非就是多考虑一个垃圾之间的等待时间

显而易见吃的情况:
dp[i][j] = dp[i-1][j] + add_life - wait_time (要在线地减去等待时间,下同)
不过转移之前想想会出现什么别的情况?
没错。如果在当前第i个垃圾到来前奶牛时间就用光了,上一个状态是没法到达当前状态的
从方程得知当前状态 dp[i][j] 会从 dp[i-1][j] 转移过来
所以判断 if ( dp[i-1][j]-wait_time < 0 ), 若是则不能进行转移

堆的情况: (此时的 dp[i][j] 是上面吃的方程刚更新出来的或未更新的dp 数组初始值)
dp[i][j] = max(dp[i][j], dp[i-1][j - add_h] - wait_time)
同样要加一个上面的判断,if ( dp[i-1][j - add_h] - wait_time > 0)
并且还要加一个 if (j - add_h ≥ 0)防止访问负下标

由于 i j是按递增顺序正向枚举的,第一个满足 j ≥ H 并且 dp[i][j] ≥ 0 (还活着) 的状态就是答案,直接输出,return 0;

初始化还有一个全赋负数的操作,这是一个细节问题
因为 dp[i][j] ≥ 0 是答案产生的条件之一,且dp值为0的时候也是合法的,会计入最终答案
而定义数组时值默认是0
所以dp值要初始化成 < 0 防止未被更新的空状态变成答案!(这个漏了就是全WA)

结局2

dp枚举完了还没输出就是死在坑里了(悲)
从一开始一直吃垃圾吃到饿死,输出最终存活时间,return 0;

代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int dp[101][101];
struct rubbish
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值