动态规划(01背包): 小U生活事件快乐值最大化 | 豆包MarsCodeAI刷题

77 阅读3分钟

题目链接

小U生活事件快乐值最大化

前置知识

01背包

01背包即给定背包容量nn,给定物品重量ww和价值vv,每个物品只能选一次,求在容量满足的情况下能得到的最大价值

分析一下,第一想法必然是贪心,我从价值大的往价值小的选,为什么不行? 假设

n = 5 w = [2,3,4] v = [2,3,4]
此时按照价值排序,会选出[4] 得到价值4 但很明显有更优的选择[2,3]得到价值5

再次分析,我们从每个物品的性价比来选(性价比相同取w小的)可行吗?
假设

n = 5 w = [1,5] v = [10,11] 此时性价比为[10,2.2][10,2.2], 会优先选择[1] 得到价值10, 而不是最优解[5] 价值11

OK, 可以看出贪心只能达到局部最优,不能得到全局最优
换一种思路

n = 5 w = [2,3,4] v = [2,3,4]
我们拿一个数组f来记录容量为ii的最大价值
假设我们要装第一个物品w1w_1 我们至少需要容量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]不做使用

此时我们尝试装入第二个物品w2w_2, 需要容量3

  • f[5]可以装w2w_2,剩余容量2,正好可以把容量2(f[2])的物品也装一起, f[5] = 3 + f[2],在上一轮,f[5]装了w1w_1 , 价值是2, 此时新的价值为5 所以更新
  • f[4]装w2w_2,剩余空间1,可以把容量1(f[1])的 装上 f[4] = 3 + f[1] = 3 比较同上
  • f[3] ...
  • f[2] 不能装,所以他的值还是装w1w_1
    此时f=[0,0,2,3,5]f = [0,0,2,3,5]
    到最后一个物品w3w_3, 需要容量4
  • f[5]可以装w3w_3 剩余容量1, 即 f[5] = 4 +f[1],值为4, 在上一轮f[5]装了物品w1w_1w2w_2的价值为5, 此时上一轮价值大于现在,所以不装w3w_3
  • f[4]可以装, 剩余0, f[4] = 4 ,上一轮得到的值是3,所以选择装w3w_3
    ....
    得到f=[0,0,2,4,5]f = [0,0,2,4,5]
    此时物品选完了 答案就是f[n=5]

上面是手推流程, 总结一下其中重复的步骤,由大规模往小规模转换
fj=max(f[j],f[jwi]+vi)f_j = max(f[j], f[j-w_i] + v_i)
f[i]f[i]表示在容量ii时能够得到的最大价值
当然,这是式子是在容量j>wij > w_i的情况下使用的
如果你理解了上面的思路,你可以完成0,1背包最大值问题

接下来,我们考虑本题

本题也称为二维费用背包,本质仍然是01背包,只是在01背包的基础上多了一个属性

解题思路

  • 简化题意:
    • 在时间<= TT && 精力 <= HH的情况下, 可以装的最多物品(事件)
    • 装物品会花费[ti,hi][t_i, h_i] 价值为aia_i
  • 我们类比01背包,时间 == 容量 这题多个一个限制精力,那么我们就定义一个二维数组
  • f[i][j]f[i][j]表示在时间ii的时候,花费jj精力能够得到的最大价值
  • 在01背包的基础上多了一层限制,我们要判断时间和精力是否都大于等于当前物品

转移方程 f[i][j]=max(f[i][j],f[it][jh]+a)f[i][j] = max(f[i][j], f[i - t][j-h]+a)

代码

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];
}