不难看出这是一道dp题,但是用什么元素去dp,需要考察。
首先一个垃圾具有三个属性,time(投喂时间),life(提供的存活时间)和height(具有的高度).时间时间没有任何的递推关系,不难想到我们有两种dp方式.
1、dp[i][j]第一维表示处理第i个垃圾,第二维表示现在存活时间为j,其值是现在的高度,我们需要用双循环,外层循环枚举所有垃圾,内层循环枚举所有存活时间,则状态转移方程是
dp[i+1][j+trash[i+1].life-(trash[i+1].time-trash[i].time]=dp[i][j] 如果牛把垃圾吃了,那么高度不会增加,也就是等于dp[i][j](上一次的高度),并且j(存活时间)改变,分为两个方面,一个是吃垃圾增加的存活时间,一个是等垃圾浪费的生命
dp[i+1][j-(trash[i+1].time-trash[i].time]=dp[i][j]+trash[i+1].height如果牛没有吃垃圾,那么他的高度等于上一次的高度dp[i][j]加上第i+1个垃圾的高度,同时注意他的存活时间也变少了,也是等垃圾浪费的生命
2、同样我们可以得出第二种dp,第一维表示处理第i个垃圾,第二维表示现在的高度,其值表示存活时间.如上分析,从是否吃垃圾两个角度得出两个状态转移方程
/*不用来吃*/dp[i+1][j+trash[i+1].height]=dp[i][j]-(trash[i+1].time-trash[i].time)
/*用来吃*/dp[i+1][j]=dp[i][j]+trash[i+1].life-(trash[i+1].time-trash[i].time)
通过对时间复杂度的分析,我们选择第二种dp,
注:我们的代码由时间顺序(第i个垃圾是第i个投放下来的)才能成立,如果输入数据连续,需要做一个排序(按trash.time排序,并且注意要交换三个属性的值,time,life,height)
如上分析看上去很正确,其实有一点小漏洞,比如如下示例,初始深度为10,有3个垃圾,第一个垃圾第1天投放,高度为4,提供存活时间为1,第二个垃圾第2天投放,高度为2,提供存活时间为2,第三个垃圾第3天投放,高度为2,提供存活时间为4,不难发现dp[3][4](处理3个垃圾,高度为4)有两种情况,第一天垫二三天吃,第一天吃二三天垫,这样就会产生值的覆盖,我们应该选取这两个值里面最高的生命值,因为更高的生命值更有希望到达上面,当然此例中无法到达.修改也很简单
/*不用来吃*/dp[i+1][j+trash[i+1].height]=max(dp[i][j]-(trash[i+1].time-trash[i].time),dp[i+1][j+trash[i+1].height]);
/*用来吃*/dp[i+1][j]=max(dp[i][j]+trash[i+1].life-(trash[i+1].time-trash[i].time),dp[i+1][j]);
只需要不停的用max来更新就可以了
并且要注意到dp[i][j]之后能否活命的问题,如果这个时候存活时间也就是dp[i][j]的值不能撑到第i+1个垃圾投放,也就不存在上述dp,所以一定要判断dp[i][j]大于等于trash[i+1].time-trash[i].time才能进行状态转移处理第i+1个垃圾吃或者垫.
最后如果高度在垫了i+1个垃圾之后(只有垫了才会增加高度,如果仅仅是用来吃了,高度只会和处理第i个垃圾之后一样)也就是j+trash[i+1]大于等于我们需求的高度d(注意也要判断是否存活),便立即输出(这样一旦爬出去了便能输出,处理的垃圾序号i越小,爬出的时间越小,最小的爬出时间才符合题意)第i+1个垃圾投放的时间(刚投放就立即处理最优),输出后return 0结束程序。
最后,考虑到有时候无论如何都上不去,那只能开摆一直吃了,如果牛现在的存活时间能撑过两个垃圾的投喂间隔,他就能吃上并续命,然后继续判断,一直到没有垃圾或者撑不住了.把存活时间存在一个maxt中,maxt的初始值是10,如果上述dp没有return 0,那说明不能完成任务,就可以输出maxt,否则会在输出前结束程序.