题目链接
前置知识
01背包
01背包即给定背包容量,给定物品重量和价值,每个物品只能选一次,求在容量满足的情况下能得到的最大价值
分析一下,第一想法必然是贪心,我从价值大的往价值小的选,为什么不行? 假设
n = 5 w = [2,3,4] v = [2,3,4]
此时按照价值排序,会选出[4] 得到价值4 但很明显有更优的选择[2,3]得到价值5
再次分析,我们从每个物品的性价比来选(性价比相同取w小的)可行吗?
假设
n = 5 w = [1,5] v = [10,11] 此时性价比为, 会优先选择[1] 得到价值10, 而不是最优解[5] 价值11
OK, 可以看出贪心只能达到局部最优,不能得到全局最优
换一种思路
n = 5 w = [2,3,4] v = [2,3,4]
我们拿一个数组f来记录容量为的最大价值
假设我们要装第一个物品 我们至少需要容量2
- f[5] 表示容量为5 可以装 所以f[5] = 2 , 此时剩余容量3
- f[4] 同上 f[4] = 2 , 剩余容量2
- f[3] 同上 f[3] = 2 , 剩余容量1
- f[2] 同上 f[2] = 2 , 剩余空间0
- f[1] 不行,f[1] = 0, 剩余容量1
此时f = [0,0,2,2,2] f[0]不做使用此时我们尝试装入第二个物品, 需要容量3
- f[5]可以装,剩余容量2,正好可以把容量2(f[2])的物品也装一起, f[5] = 3 + f[2],在上一轮,f[5]装了 , 价值是2, 此时新的价值为5 所以更新
- f[4]装,剩余空间1,可以把容量1(f[1])的 装上 f[4] = 3 + f[1] = 3 比较同上
- f[3] ...
- f[2] 不能装,所以他的值还是装
此时
到最后一个物品, 需要容量4- f[5]可以装 剩余容量1, 即 f[5] = 4 +f[1],值为4, 在上一轮f[5]装了物品和的价值为5, 此时上一轮价值大于现在,所以不装
- f[4]可以装, 剩余0, f[4] = 4 ,上一轮得到的值是3,所以选择装
....
得到
此时物品选完了 答案就是f[n=5]
上面是手推流程, 总结一下其中重复的步骤,由大规模往小规模转换
表示在容量时能够得到的最大价值
当然,这是式子是在容量的情况下使用的
如果你理解了上面的思路,你可以完成0,1背包最大值问题
接下来,我们考虑本题
本题也称为二维费用背包,本质仍然是01背包,只是在01背包的基础上多了一个属性
解题思路
- 简化题意:
- 在时间<= && 精力 <= 的情况下, 可以装的最多物品(事件)
- 装物品会花费 价值为
- 我们类比01背包,时间 == 容量 这题多个一个限制精力,那么我们就定义一个二维数组
- 表示在时间的时候,花费精力能够得到的最大价值
- 在01背包的基础上多了一层限制,我们要判断时间和精力是否都大于等于当前物品
转移方程
代码
int solution(int n, int T, int H, std::vector<int> t, std::vector<int> h, std::vector<int> a) {
vector<vector<int>>f(T+1, vector<int>(H+1,0));
for(int i=0; i < n; i++) {
for(int j = T; j >= t[i]; j--) {
for (int k = H; k >= h[i]; k--) {
f[j][k] = max(f[j][k],f[j-t[i]][k-h[i]]+a[i]);
}
}
}
return f[T][H];
}