代码随想录算法训练营第四十二天|背包问题理论基础、01背包理论基础(滚动数组)、416. 分割等和子集
背包问题理论基础
背包问题理论基础
文章讲解:https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html
题目链接:https://kamacoder.com/problempage.php?pid=1046
视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6/
自己看到题目的第一想法
看完代码随想录之后的想法
先列出物品的重量、价值表格。
重量 | 价值 | |
---|---|---|
物品0 | 1 | 15 |
物品1 | 3 | 20 |
物品2 | 4 | 30 |
得到dp[i][j]的定义
动态规划五步骤:
-
dp[i][j]的定义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
-
递推公式:不放物品i的时候,最大价值为dp[i-1][j](其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。因此在循环时会有背包大小的判断);放物品i的时候最大价值为dp[i-1][j - wight[i]] + value[i](当i放进去时,那么这时候整个物品集就被分成两部分,1到i-1和第i个,而这是i是确定要放进去的,那么就把j空间里的wight[i]给占据了,只剩下j-wight[i]的空间给前面i-1,那么只要这时候前面i-1在j-wi空间里构造出最大价值,即dp[i-1][j - wight[i]],再加上此时放入的i的价值vi,就是dpij了);所以递推公式dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j - wight[i]] + value[i]);见下面表格,dp[i][j]由其上一个节点以及左上某一节点得到。
-
初始化值:画出背包重量和物品的二维数组图。见下图可以得出dp[0][j]这一行的值为15。dp[i][0]这一列的初始值为0。
-
遍历顺序
- for() ----- 物品
- for()----背包
这里进行遍历的时候需要增加一个当前重量放不下的判断。
- for()----背包
- for() ----- 物品
自己实现过程中遇到哪些困难
将2个数组入参改为二维数组,然后处理逻辑。
做动态规划的题目,最好的过程就是自己在纸上举一个例子把对应的dp数组的数值推导一下,然后在动手写代码!
01背包理论基础(滚动数组)
01背包理论基础(滚动数组)
文章讲解:https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-2.html
题目链接:https://kamacoder.com/problempage.php?pid=1046
视频讲解:https://www.bilibili.com/video/BV1BU4y177kY/
自己看到题目的第一想法
看完代码随想录之后的想法
- dp[j]的定义:容量为j的背包所背最大价值为dp[j]。
- 递推公式:滚动数组是把上一行的数组拷贝到当前行,因此当前层不放物品i的最大价值就为dp[j],再按照二维数组的方式列出dp[i][j]的推导公式,dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j - wight[i]] + value[i]); -》最终dp[j] = Math.max(dp[j],dp[j - wight[i]] + value[i]);
- 初始化:背包容量为0时最大价值肯定为0因此dp[0] = 0;
- 遍历顺序
for (i=0;i<物品数量;i++) 物品
for(j=bagweight; j>=weight[i];j–) 背包 为什么倒序遍历?? 因为正序遍历相同的物品会被添加2次,不符合01背包的规则。
一维dp数组只能先遍历物品再遍历背包。
背包问题可以出一个完整的01背包题目,比如互换遍历顺序,二维转一维等。回顾的时候再看一看
自己实现过程中遇到哪些困难
分割等和子集
416. 分割等和子集
文章讲解:https://programmercarl.com/0416.%E5%88%86%E5%89%B2%E7%AD%89%E5%92%8C%E5%AD%90%E9%9B%86.html
题目链接:https://leetcode.cn/problems/partition-equal-subset-sum/
视频讲解:https://www.bilibili.com/video/BV1rt4y1N7jE/
自己看到题目的第一想法
没有背包的思路。
看完代码随想录之后的想法
[1,5,11,5]所有的数相加,然后除以2即为最大背包值。然后每个元素只能使用一次,因此就为01背包问题。
背包问题的话有一个重量和价值,这里价值=重量,判断能求得等和子集的条件为target=sum/2;最大价值dp[target] = target。
动规五步曲:
- 确定dp数组以及下标含义
- dp[j]表示背包总容量是j,放进物品后背的最大重量是dp[j]。
- 确定推导公式
01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。
所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
- 确定初始值
- 当背包大小为0时,值为0。dp[0] = 0;其他位置的初始值也使用0即可。
- 确定遍历顺序
- 根据一维数组的01背包,先遍历物品然后再遍历重量,遍历重量时从后往前遍历。
- 输出值
自己实现过程中遇到哪些困难
递推公式没出对
今日收获&学习时长
背包问题完成的比较潦草,等后续二刷
学习时长:1小时