代码随想录刷题| 多重背包理论基础、背包问题的总结

目录

多重背包理论基础

多重背包的问题

多重背包的解法

多重背包的代码

背包问题的总结

01背包

完全背包

多重背包


多重背包理论基础

多重背包的问题

  • 有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大

多重背包的解法

  • 多重背包问题可以使用01背包的思路去解决
  • 既然物品的数量是固定,就可以使用01背包,只不过其中的物品有重复
  • 假设现在有个背包如下:
  • 可以将这个多重背包转换成:
  • 这就可以看成一个01背包问题了 

多重背包的代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MultiBagProblem {
    public static void main(String[] args) {

        // 物品信息
        /**
         *          重量  价值  数值
         *  物品0     1    15    2
         *  物品1     3    20    3
         *  物品2     4    20    2
         */
        List<Integer> weight = new ArrayList<>(Arrays.asList(1,3,4));
        List<Integer> value = new ArrayList<>(Arrays.asList(15,20,30));
        List<Integer> nums = new ArrayList<>(Arrays.asList(2,3,3));

        // 背包信息
        int bagSize = 10;

        multiBag(weight,value,nums,bagSize);
    }


    /**
     *
     * @param weight  物品的重量
     * @param value   物品的价值
     * @param nums    物品的数量
     * @param bagSize 背包的容量
     */
    private static void multiBag(List<Integer> weight,
                          List<Integer> value,
                          List<Integer> nums,
                          int bagSize) {
        /**
         * 将物品展开
         */
        // 先把物品展开,展开成一个物品只有一个
        for (int i = 0; i < nums.size(); i++) {
            while (nums.get(i) > 1) {
                weight.add(weight.get(i));
                value.add(value.get(i));
                nums.set(i , nums.get(i) - 1);   // 展开一个,原数量就减一
            }
        }

        /**
         * 按照01背包进行装包
         */
        // 创建dp数组
        int[] dp = new int[bagSize+1];

        // 遍历更新dp数组
        for (int i = 0; i < weight.size(); i++) {  // 先对物品进行遍历
            for (int j = bagSize; j >= weight.get(i); j--) {  // 再对背包进行倒序遍历
                dp[j] = Math.max(dp[j],dp[j-weight.get(i)] + value.get(i));
            }

            // 打印dp数组
            System.out.println("物品" + i + "\t" + Arrays.toString(dp));
        }
    }
}

背包问题的总结

01背包

  • 01背包是重中之重
  • 01背包:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大
  • 主要有以下几种问题:
    • 1、求物品装进背包中的最大价值(纯01背包)
      • 递推公式原理为:dp[ j ] = max( dp[ j ] , dp[ j - weight[ i ] ] + value[ i ]);
      • 对应的题目
        • 416.分割等和子集
        • 1049.最后一块石头的重量||
    • 2、求物品装满背包的方法数 
      • 递推公式原理为:dp[ j ] += dp[ j - weight[ i ] ]
      • 由于方法数是逐步积累的,所以初始化应该是dp[ 0 ] = 1
      • 对应的题目
        • 494.目标和
    • 3、求最终背包中的物品数
      • 递推公式原理为:dp[ j - weight[ i ] + 1]
      • 如果是求最大个数:就是dp[ j ] = max(dp[ j ],dp[ j - weight[ i ] ] + 1 );由于是求最大值,初始化时dp[0] = 0,其余的也为0。对应的题目有 474.一和零
      • 如果是求最小个数:就是dp[ j ] = min(dp[ j ],dp[ j - weight[ i ] ] + 1 );由于是求最小值,初始化时dp[0] = 0,其余的为MAX_VALUE。对应的题目有 322.零钱兑换

完全背包

  • 01背包的时候,为了使物品在向背包中添加的时候保证物品只添加一次,在遍历背包的时候使用倒序遍历
  • 那完全背包中的物品是可以被重复添加的,那么在遍历背包的时候使用正序遍历,就可以保证物品被多次添加
  • 主要有以下几种问题
    • 1、求物品装进背包中的最大价值(纯完全背包)
      • 递推公式原理为:dp[ j ] = max( dp[ j ] , dp[ j - weight[ i ] ] + value[ i ]);
    • 2、求物品装满背包的方法数 
      • 递推公式原理为:dp[ j ] += dp[ j - weight[ i ] ]
      • 由于方法数是逐步积累的,所以初始化应该是dp[ 0 ] = 1
      • 对应的题目
        • 518.零钱兑换|| —— 求组合数 —— 先遍历物品再遍历背包
        • 377.组合总和IV —— 求排列数 —— 先遍历背包再遍历物品
        • 70.爬楼梯 —— 求排列数 —— 先遍历背包再遍历物品
    • 3、求最终背包中的物品数
      • 递推公式原理为:dp[ j - weight[ i ] + 1]
      • 如果是求最小个数:就是dp[ j ] = min(dp[ j ],dp[ j - weight[ i ] ] + 1 );由于是求最小值,初始化时dp[0] = 0,其余的为MAX_VALUE
      • 对应的题目
        • 322.零钱兑换 
        • 279.完全平方数

多重背包

  • 多重背包的解决方案就是将多重背包转换成01背包进行处理
  • 原理上并没有什么难点,等遇到相应的题目再说
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值