【算法】---- 01背包问题和完全背包问题LeetCode系列问题题解

背包问题:

  • 背包:最大容量v
  • 物品:
    • 物品价值w
    • 物品体积v
    • 每个物品的数量
      • 只有一个(01背包)
      • 无数个(完全背包)

例子:

有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

背包最大重量为4。

物品为:

重量 价值
物品0 1 15
物品1 3 20
物品2 4 30

问背包能背的物品最大价值是多少?

1、01背包入门

1.1 二维背包

/**
 * 背包最大重量为4
 *
 *        重量    价值
 * 物品0    1     15
 * 物品1    3     20
 * 物品2    4     30
 *
 *
 */

/**
 * 思路: 二维dp数组01背包
 *
 * 1. 确定dp数组以及下标含义
 * dp[i][j]: 表示从下标为0~i的物品任意取,放进容量为j的背包,价值总和最大是多少
 *
 * 2. 确定递推公式
 * if(j < weight[i]) {
 *    dp[i][j] = dp[i-1][j];
 * } else {
 *        dp[i][j] = Math.max(dp[i-1][j-weight[i]] + value[i], dp[i-1][j])
 *                       放入物品i                        不放入物品i
    * }
 *
 * 3. 初始化
 * 背包容量为0时, 即j = 0 时, dp[i][0] = 0
 *
 * i = 0时
 * for(int j = weight[0]; j <= bagweight; j++) {
 *     dp[0][j] = value[0];
 * }
 *
 * 4. 确定遍历顺序
 * 先遍历物品,再遍历背包容量; 反之也可以
 * 从上到下,从左往右
 *
 * 5. 举例推导dp数组
 *        重量
 *         0   1  2  3  4
 * 物品0    0  15 15 15 15
 * 物品1    0  15 15    20 35
 * 物品2    0  15 15 20 35
 *
 *
 * 时间: O(n*m)
 * 空间: O(n*m)
 * n为物品,m为重量
 */
static void wei_bag_problem() {
   
   int[] weight = {
   1,3,4};
   int[] value = {
   15,20,30};
   int bagWeight = 4;

   // 1. 确定dp数组以及下标含义
   // 二维数组
   // dp[i][j] 代表下标[0-i]物品里任意取,放进容量为j的背包,价值总和最大是多少
   int[][] dp = new int[weight.length][bagWeight + 1];

   // 2. 初始化
   // 背包重量为0的 dp[i][0]价值为0
   for (int i = 0; i < weight.length; i++) {
   
      dp[i][0] = 0;
   }

   // 存放编号为0的物品的时候, 各个容量的背包所能存放的最大价值
   // 倒叙遍历
   /*for (int j = bagWeight; j >= weight[0]; j--) {
      dp[0][j] = dp[0][j - weight[0]] + value[0];
   }*/

   // 正序遍历
   for (int j = weight[0]; j <= bagWeight; j++) {
   
      dp[0][j] = value[0];
   }

   // 3. 遍历顺序
   for (int i = 1; i < weight.length; i++) {
    // 遍历物品
      for (int j = 1; j <= bagWeight; j++) {
    // 遍历背包容量
         if(j < weight[i]) {
   
            dp[i][j] = dp[i - 1][j];
         } else {
   
            dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]);
         }
      }
   }

   System.out.println(dp[weight.length-1][bagWeight]);
}

1.2 一维背包

public class _01_背包_一维 {
   

   /**
    * 背包最大重量为4
    *
    *        重量    价值
    * 物品0    1     15
    * 物品1    3     20
    * 物品2    4     30
    *
    *
    */

   /**
    * 思路: 一维数组01背包
    *
    * 1. 确定dp数组以及下标含义
    * dp[j]: 表示容量为j的背包的最大价值
    *
    * 2. 确定递推公式
    * dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i])
    *               不放入当前物品     放入当前物品
    *
    * 3. 初始化
    *      dp[0] = 0
    *
    * 4. 确定遍历顺序
    * 先遍历物品,再遍历背包容量
    * 遍历背包容量的时候,应该是倒叙遍历
    *
    * 如果是正序遍历的话
    * dp[1] = dp[1-weight[0]] + value[0] = 15
    * dp[2] = dp[2-weight[0]] + value[0] = 15 + 15 =  30
    * 重复放了2次
    *
    * 如果是倒叙遍历的话
    * dp[2] = dp[2-weight[0]] + value[0] = 15
    * dp[1] = dp[1-weight[0]] + value[0] = 15
    *
    * 5. 举例推导递推公式
    *      背包容量:   0  1  2  3  4
    * 用物品0,遍历背包: 0 15 15 15 15
    * 用物品1,遍历背包: 0 15 15 20 35
    * 用物品2,遍历背包: 0 15 15 20 35
    */
   public static void wei_bag_problem() {
   
      int[] weight = {
   1,3,4};
      int[] value = {
   15, 20, 30};
      int bagweight = 4;

      // 1. 确定dp数组及下标含义
      // dp[j] 表示容量为j的背包,价值总和最大是多少
      int[] dp = new int[bagweight+1];

      // 2. 确定递推公式
      // dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]) 不放入物品, 放入物品
      // 所以一维数组时,递推公式如下
      // dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i])

      // 3. 初始化
         // 要和dp数组的定义吻合
      // 若价值都为正整数,则全部初始化为0, 如果出
  • 5
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值