2212. 射箭比赛中的最大得分
打周赛遇到的一道非常典型的0-1背包问题,但是因为太久没写过背包问题,写了40分钟才写出来,再温习一遍。
什么是0-1背包?
一共有N个物品,每个物品有对应的重量weight[i] 和价值value[i],给定一个固定容量W的背包,问能够放入背包的最大价值是多少?非常经典又相对简单的动态规划问题,关键还是在于定义状态以及状态转移公式。
贪心的角度出发,假设我选取某个物品后,新的贪心目标变为 在剩余物品和空间的条件下,选取最大价值的物品,因此父问题到子问题的转化可以定义为:(按照从左到右一个一个选的思路)
- 父问题:是否选取第i个物品,使得总价值最大
- 子问题:父问题 选 / 不选 第i个物品, 背包剩余 W-w[i] / W空间,如何在前i-1物品中合适选取使得子问题价值最大
dp状态可以定义为:
1 | dp[i][j]: 将前i个物品装到容量为j的背包中的最大价值 |
状态转移公式为:
选取第i个物品
1
dp[i][j] = v[i] + dp[i][j - w[i]]
不选第i个物品(或者当前容量无法选取第i个物品)
1
dp[i][j] = dp[i - 1][j]
最后公式为
1
dp[i][j] = max(v[i] + dp[i][j - w[i]], dp[i - 1][j])
复杂度分析:
- 时间复杂度:自下而上(前i物品)计算状态,每个物品需要遍历所有的背包容量,时间复杂度为 O(NW),即物品数量乘以背包容量
- 空间复杂度: 类似时间复杂度分析,存储所有状态需要 O(NW),若使用存储压缩,只需要一个长度等于背包容量的数组,但是若要存储解,则无法压缩,空间复杂度为 O(NW) 或者 O(W)
模板伪代码:
1 | # dp数组长度为w+1,多一个为了减少越界判断 |
射箭问题
非常明显的0-1背包问题,箭支数量为”背包容量”,占领每个区域所需要的箭为”物品重量“,每个区域的分数为”价值”,转化为0-1背包问题套模板即可,代码如下:
1 | class Solution { |