这是一道经典的USACOUSACOUSACO动态规划题。
思路
把垃圾按时间TTT从小到大排序。设:
dp[i][j]dp[i][j]dp[i][j]:处理到第iii个垃圾(按时间排序后),当前堆叠高度为jjj时,卡门剩余的最大存活时间(即"当前时刻 + 剩余能量")。如果该状态不可达则为负无穷。
转移时对第 i 个垃圾(时间ttt,食物fff,高度hhh)有两种选择:
1.
吃掉:高度不变,dp[i][j]=hmax(dp[i][j],dp[i−1][j]+f)dp[i][j] = hmax(dp[i][j], dp[i-1][j] + f)dp[i][j]=hmax(dp[i][j],dp[i−1][j]+f)
2.
堆起来: dp[i][j]=max(dp[i][j],dp[i−1][j−h])dp[i][j] = max(dp[i][j], dp[i-1][j-h])dp[i][j]=max(dp[i][j],dp[i−1][j−h]) (要求j>=hj >= hj>=h且dp[i−1][j−h]>=tdp[i-1][j-h] >= tdp[i−1][j−h]>=t,即在该垃圾落下时卡门还活着)
初始dp[0][0]=10dp[0][0] = 10dp[0][0]=10(初始 10 小时能量)。
由于D≤100D ≤ 100D≤100,高度这一维最多到DDD(超过DDD就算逃出去了,不需要再记录)。
答案判定:
在所有dp[i][j]>=tidp[i][j] >= t_idp[i][j]>=ti 且$ j + h_i >= D$的状态中,取最小的 tit_iti 作为逃出时间。如果无法逃出,则答案为所有可达状态 dp[G][j]dp[G][j]dp[G][j] 的最大值(即最长存活时间)。
细节:
题目说"若体力值为 0 时吃下垃圾或逃出井外也不会饿死",且"10 小时内(不含 10 小时)没有进食会饿死"。这意味着卡门在时刻xxx死亡当且仅当她的"死亡时间"(当前时间 + 剩余能量)严格小于 下一个要处理的垃圾落下时间。因此转移时要求dp[i−1][j−h]>=tdp[i-1][j-h] >= tdp[i−1][j−h]>=t(等于ttt时刚好能撑到垃圾落下,不算饿死)。
C++代码:
注意:上面代码在"堆放"转移时有个细节——当J+H>=DJ + H >= DJ+H>=D时直接判断逃出,不再更新DPDPDP。这等价于把高度上限设为DDD,因为超过DDD的状态对后续无意义(已经逃出了)。另外,由于一维滚动数组从大到小遍历,同一垃圾不会被重复用于堆放。