动态规划之背包问题
引言
背包问题是动态规划问题中一类非常经典的问题,有很多可以思考的地方,网上有很多博主都有很多高质量的文章,但是各自分析的角度不同,这篇文章是结合网上很多高质量文章之后,自己总结的一些值得注意的点。
整体分析思路
主要参考了代码随想录、Acwing算法基础课、夜深人静写算法的思路。
Acwing算法基础课
其中Acwing算法基础课的思路较为简练,从集合的角度来理解动态规划,主要分为两个步骤:状态表示跟状态计算(转移)。
在状态表示部分,从集合的角度理解DP的话,可以分为两个步骤,一个是确立集合的含义,一个是确立集合的属性(max, min, sum)。加上确立属性这一硬性步骤进行思考的话,出错率会减少。
代码随想录
代码随想录的思路更为具体,按照该思路去做,不容易出问题。
- 状态表示:确定dp数组以及下标的含义
- 状态计算:确定递推公式
- 初始化dp数组
- 确定遍历顺序:比如先遍历物品还是先遍历重量,从小到大遍历还是从大到小遍历
- 举例推导dp数组
夜深人静写算法
思路总结
这三者的整体思路是一致的,都包括状态表示跟状态计算(转移),代码随想录跟夜深人静写算法都强调了初始化。
自己做题的时候,可以以代码随想录的思路去做,特别是要思考初始化、确定遍历顺序以及举例推导dp数组后三个步骤。
对于01背包的空间优化,可以先按照二维的思想去做,然后做等价变形。
对于完全背包的空间优化,还没整明白。
过程中遇到的问题
主要在初始化、确定遍历顺序上面有些问题。
初始化
代码随想录是把0当作第一个物品,yxc是把1当作第一个物品。
这会影响到初始化的步骤,前者需要人为思考并赋值,而后者好像只需要赋值f[0][0] = 0,1就可以。
比如对于494.目标和这道题目,如果把0当作第一个物品的话,初始化的时候略有些复杂, 第一次想很难想全面。
确定遍历顺序
先根据代码随想录把几个结论记录下来。
二维的01背包:先遍历物品跟先遍历背包容量都可以
一维的01背包:只能先遍历物品
一维的完全背包:两个for循环嵌套顺序无所谓
在377. 组合总和 Ⅳ这道题目中,不同的遍历顺序含义不一样,对应的结果也不一样。
遍历顺序决定着状态的转移,如果画图的话,可以看出状态是从哪个方向转移过来的。
力扣具体题目
01背包
遇到的坑,对于状态表示部分,自己对于集合的选取没问题,但是对于属性(最大值,最小值,总和)经常忘记去思考,导致最后结果出错。
杂
发现宫水三叶的背包讲的也还可以