代码随想录算法训练营第四十二天|背包问题理论基础、01背包理论基础(滚动数组)、416. 分割等和子集

代码随想录算法训练营第四十二天|背包问题理论基础、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]由其上一个节点以及左上某一节点得到。代码随想录算法训练营第四十二天|背包问题理论基础、01背包理论基础(滚动数组)、416. 分割等和子集_第1张图片

  • 初始化值:画出背包重量和物品的二维数组图。见下图可以得出dp[0][j]这一行的值为15。dp[i][0]这一列的初始值为0。代码随想录算法训练营第四十二天|背包问题理论基础、01背包理论基础(滚动数组)、416. 分割等和子集_第2张图片

  • 遍历顺序

    • 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. 分割等和子集_第3张图片
    背包问题可以出一个完整的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小时

你可能感兴趣的:(算法)