leetcode01背包问题(C++)
目录
1.背包问题概述
2.01背包模板问题(牛客网)
3.分割等和子集
4.目标和
5.最后一块石头的重量 ||
6.01背包问题总结
1.背包问题概述
背包问题是什么?
假设你有一个背包,挑选一些物品放入背包中,提问最大能挑出来的价值是多少
物品、背包都有其属性,例如重量、大小还有价值……
0-1背包问题:每个物品限制只有1个
完全背包问题:每个物品有无穷多个
背包有不必装满、必须装满2种情况
2.01背包模板问题(牛客网)
第一问是说背包没装满或装满的情况下,至多能拿多少价值的物品
第二问是说背包必须装满的情况下,至多能拿多少价值的物品。如果无法装满,就输出0(2问都是基于0-1背包问题提出,即每个物品只有1个)
问题1解答:
1.状态表示(经验+题目要求):
鉴于该题有体积作为限制条件,因此我们最好用一个二维数组来表示状态。
dp[i][j]表示:从前 i 个物品中选,总体积不超过j(不超过说明可以呈现小于等于关系),所有选法中,能挑出来的最大价值(如此就能物品的价值、体积都考虑到了)
2.状态转移方程(根据最后一步的状况,分情况讨论得出):
假设到了第i个物品,不选i物品时那就是从[1,i-1]范围中找到最大值,恰好就是dp[i-1][j];若选择了i物品作为答案中的一部分,则先得保证 j >= V[i],要不然书包装不下这么大体积的物品(例如选到i物品时要求体积不能超过4(j = 4),i 物品的体积为5(V[i] = 5),这种情况下因为装不下所以可以跳过了);因为需要给i物品预留下V[i]的背包空间,因此在[1,i-1]范围内,最多只能使用 j - V[i] 的空间(即总体积最多不能超过j - V[i]),因此最后dp[i][j] = dp[i-1][j-V[i]] + W[i](该物品的价值);此处需要注意的是:j 是动态的,即逐渐变大,需要把一整行所有的数组全部遍历一遍(即用j的背包大小装某个可能没有j大的元素且 “j<=V(背包大小)” ,即使装完还有非常大的背包体积浪费掉照装不误),动态规划的代码会帮助我们找到最好的情况;并且还需要比较硬要装包的情况还有再装一个物品哪一个更好(就比如用10体积装了个体积为8、价值为100的物品;即使换成2个体积为5的、价值分别为25的物品,但显然也是前者更好),即max(dp[i-1][j],dp[i-1][j-V[i]]+w[i])
3.dp方程初始化:
在状态转移方程中,会用到 i - 1,为防止数组越界,所以需要加一行;列的属性都是物品大小,物品大小不可能出现0,只会是在[1,V]范围内,所以可以加一列来加强代码可读性。加的行与列初始化都是0,即没有选取任何物品放到背包。
4.填表顺序:
如上图所示,因此是从上往下、从左往右即可
5.返回值:
在n个物品中选取,总体积不能超过背包大小V,这种情况下得到的即为最优解,因此返回dp[n][V]
以示例1为例,下图清晰表现了示例1的整个运行过程
问题2解答:
1.状态表示:
vp[i][j]表示:从前i个物品中去选,总体积正好等于j,所有选法中,能挑选出来的最大价值
2.状态转移方程:
我们把 vp[i][j] == -1作为该种选法不可行的判断,那么为什么不能把 vp[i][j] == 0作为该选法不可行呢?如上图(示例1情况