动态规划day04(01背包问题)

这篇具有很好参考价值的文章主要介绍了动态规划day04(01背包问题)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

01背包问题(二维数组和滚动数组)

本题力扣上没有原题,大家可以去卡码网第46题 (opens new window)去练习,题意是一样的。

《代码随想录》算法视频公开课 (opens new window):带你学透0-1背包问题! (opens new window),相信结合视频再看本篇题解,更有助于大家对本题的理解

这周我们正式开始讲解背包问题!

背包问题的经典资料当然是:背包九讲。在公众号「代码随想录」后台回复:背包九讲,就可以获得背包九讲的pdf。

但说实话,背包九讲对于小白来说确实不太友好,看起来还是有点费劲的,而且都是伪代码理解起来也吃力。

对于面试的话,其实掌握01背包,和完全背包,就够用了,最多可以再来一个多重背包。

看到题目的第一想法

       装入背包的最大价值

        维度

        重量:weight

        价值:value

        背包容量:j

        物品数量:i

看到代码随想录之后的想法(二维数组)

       1 dp数组的定义和下标的含义

        dp[i][j] 物品0~i之间能填入背包j的最大价值

        2 确定递推公式

         对于物品i 我们只有两种选择

        1 若选择物品i  则最大值为 dp[i-1][j-weight[i]]+value[i]  

        2 若不选择物品i 则最大值为选择上一个物品的最大值 dp[i-1][j]

         dp[i][j] =Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]); 

        3 dp数组初始化

        由于需要 i-1 的值 则需要把第一行初始化:

        当j<weight[i]  dp[0][j]=0

        当j>=weight[i] dp[0][j]=weight[i]

        4 确定遍历顺序

        先物品后背包

        先背包后物品 都可以

        5 举例推导dp数组

自己实现过程中遇到的困难(二维数组)

       1 确定dp[i][j]时,若weight[i]>j 则没法取第二种情况,直接取第一种情况dp[i-1][j]

        2 行列需要确认好,最好画图

看到代码随想录之后的想法(滚动数组)

        将二维数组压缩成一维数组,只看一维数组中的内容

        当选择新的物品时,一维数组中的内容,是上一层一维数组中的所有结果

       1 dp数组的定义和下标的含义

        dp[j] 物品0~i之间能填入背包j的最大价值

        2 确定递推公式

         对于物品i 我们只有两种选择

        1 若选择物品i  则最大值为 dp[j-weight[i]]+value[i]  

        2 若不选择物品i 则最大值为选择上一个物品的最大值 dp[j]

         dp[i][j] =Math.max(dp[j],dp[j-weight[i]]+value[i]); 

        3 dp数组初始化

        只有一行,全为0

        4 确定遍历顺序

        只能先物品后背包 

        因为最新一行只能取上一行的内容来确认,要确保每一行都处理完

        且只能从后往前遍历:如果从前往后,会把之前的数据打乱,而后续的数据需要依赖前面的数据

        5 举例推导dp数组

自己实现过程中遇到的困难(滚动数组)

       1 确定dp[j]时,若weight[i]>j 则没法取第二种情况,直接取第一种情况

        2 行列需要确认

import java.util.*;
 
public class Main {
    //卡哥做法:一维数组
        //1 确认dp数组,以及dp数组下标的含义
        // dp数组 一维数组 dp[j]
        // 相当于讲二维数组进行一个压缩,每次只取最后一行(第i层)
        // 一维数组都是利用上一层的结果推出第i层的值
        // 下标的含义 任意取物品0~i可存入空间为j的背包的最大值
        //2 确定递推公式
        // 对于物品i 有两种选择 取两者中的最大值
        // 1 取物品i: 则当前i j 的value 为 dp[i-1][j-weight[i]]+value[i]
        // 一维数组: dp[j]=dp[j-weight[i]]+value[i]
        // 2 不取物品i:则当前 i j 的value 为dp[i-1][j];
        // 一维数组: dp[j]=dp[j]
        // 若weight[i]>j 则没法取第一种情况,直接取第二种情况
        // Math.max(dp[j],dp[j]-weight[j]);
        //3 dp数组如何初始化
        // dp[j] 的值来自 dp[j] dp[j-weight[i]]
        // 若初始化,不能让dp[j]过大,所以统一为最小非负数0
        //4 确定遍历顺序
        //从后往前,因为j-weight[i] 是需要获取这一行前面的值
        //若从前往后,则会打乱上一层留下来的值 无法获取正确的j-weight[i]值
        // 按行列都可以
        //5 举例推导dp数组
     public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
         
        int M = sc.nextInt();
        int size = sc.nextInt();
         
        int[] value = new int[M];
        int[] weight = new int[M];
         
        for(int i = 0; i < M;i++) {
            weight[i] = sc.nextInt();
        }
         
         
        for(int i = 0; i < M;i++) {
            value[i] = sc.nextInt();
        }
        int[] dp = new int[size+1];
        // 若比weight小则为0 若比weight大则为value
        for(int i=0;i<=size;i++){
            dp[i]=0;
             
        }
        //从i=0开始 也就是第0行就开始赋值
        for(int i=0;i<weight.length;i++){
            for(int j=size;j>0;j--){
                // 这里要加上等于
                if(j>=weight[i]){
                    dp[j]=Math.max(dp[j],dp[j-weight[i]]+value[i]);
                }else{
                    dp[j]=dp[j];
                }
            }
        }
        System.out.println(dp[size]);
}
 
     
/*    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
         
        int M = sc.nextInt();
        int size = sc.nextInt();
         
        int[] value = new int[M];
        int[] weight = new int[M];
         
        for(int i = 0; i < M;i++) {
            weight[i] = sc.nextInt();
        }
         
         
        for(int i = 0; i < M;i++) {
            value[i] = sc.nextInt();
        }
        int[][] dp = new int[weight.length][size+1];
        for(int i=0;i<weight.length;i++){
            dp[i][0]=0;
        }
        // 若比weight小则为0 若比weight大则为value
        for(int i=0;i<=size;i++){
            if(i<weight[0]){
                dp[0][i]=0;
            }else{
                dp[0][i]=value[0];    
            }
        }
        for(int i=1;i<weight.length;i++){
            for(int j=1;j<=size;j++){
                // 这里要加上等于
                if(j>=weight[i]){
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                }else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        System.out.println(dp[weight.length-1][size]);
    }*/
}    
/*    
    // weight 空间,value代表价值,size 代表行李空间
    public static int bagProblem(int[] weight,int[] value,int size){
        //卡哥做法:
        //1 确认dp数组,以及dp数组下标的含义
        // dp数组 二维数组 dp[i][j]
        // 下标的含义 任意取物品0~i可存入空间为j的背包的最大值
        //2 确定递推公式
        // 对于物品i 有两种选择 取两者中的最大值
        // 1 取物品i: 则当前i j 的value 为 dp[i-1][j-weight[i]]+value[i]
        // 2 不取物品i:则当前 i j 的value 为dp[i-1][j];
        // 若weight[i]>j 则没法取第一种情况,直接取第二种情况
        //3 dp数组如何初始化
        // dp[i][j] 的值来自 dp[i-1][j] dp[i-1][j-weight[i]]
        // 则第一列和第一行需要有值
        // 第一列的值都为0  因为j为0
        // 第一行的值是物品0的值,当weight<j时 都为0 当weight>=j时都为物品0的weight
        //4 确定遍历顺序
        // 按行列都可以
        //5 举例推导dp数组
         
        int[][] dp = new int[weight.length][size+1];
        for(int i=0;i<weight.length;i++){
            dp[i][0]=0;
        }
        // 若比weight小则为0 若比weight大则为value
        for(int i=0;i<=size;i++){
            if(i<weight[0]){
                dp[0][i]=0;
            }else{
                dp[0][i]=value[0];    
            }
        }
        for(int i=1;i<weight.length;i++){
            for(int j=1;j<=size;j++){
                if(j>weight[i]){
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                }else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        return dp[weight.length-1][size];
         
    }
}*/
/*import java.util.*;
 
public class Main {
     
    public static void main(String[] args) {
        // 背包容量 N
        // 物品种类 M
        Scanner sc = new Scanner(System.in);
         
        int M = sc.nextInt();
        int N = sc.nextInt();
         
        int[] values = new int[M];
        int[] weights = new int[M];
         
        for(int i = 0; i < M;i++) {
            weights[i] = sc.nextInt();
        }
         
         
        for(int i = 0; i < M;i++) {
            values[i] = sc.nextInt();
        }
         
        int[][] dp = new int[M][N+1];
         
        // 初始化
        for(int i = weights[0]; i <= N; i++) {
            dp[0][i] = values[0];
        }
         
        // 先物品
        for(int i = 1; i < M; i++) {
            // 后背包
            for(int j = 0; j <= N; j++) {
                if(weights[i] > j) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weights[i]] + values[i]);
                }
            }
        }
        System.out.println(dp[M-1][N]);
    }
}*/

分割等和子集

力扣题目链接(opens new window)

题目难易:中等

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200

示例 1:

  • 输入: [1, 5, 11, 5]
  • 输出: true
  • 解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:

  • 输入: [1, 2, 3, 5]
  • 输出: false
  • 解释: 数组不能分割成两个元素和相等的子集.
看到题目的第一想法

       卡哥说可以用背包,但是我没想到

看到代码随想录之后的想法(二维数组)

        其实题意就是这个数组能否拆分成总的sum的一半

        若总和无法到达一半 ,则无法凑成

        若总和可以拆分,题意为:0~i的物品填入sum/2的背包能否填满

       1 dp数组的定义和下标的含义

        dp[j] 物品0~i之间能填入背包j的最大价值

        背包大小sum/2

        2 确定递推公式

         dp[j] =Math.max(dp[j],dp[j-weight[i]]+value[i]); 

        weight[i] 和 value[i] 都为nums[i]

        3 dp数组初始化

                都为0

        4 确定遍历顺序

        先物品后背包

        且从后往前

        5 举例推导dp数组

自己实现过程中遇到的困难(二维数组)

       1 确定dp[i][j]时,若weight[i]>j 则没法取第二种情况,直接取第一种情况dp[i-1][j]

        2 行列需要确认

        3 看dp[sum/2] 是否==sum/2文章来源地址https://www.toymoban.com/news/detail-802421.html

class Solution {
    public boolean canPartition(int[] nums) {
        //背包问题:背包存放的最大价值,看是否选中该物品,在目标背包大小中取最大值
        //该问题:背包存放的最大价值,在当前背包大小为target时,看最大价值是否能填满这个target
        //两个子集的元素和相等
        //其实就是求整个数组的和的一半,看数组中的值能否达到
        //转换成背包问题,一个背包  大小为为nums总和的一半,如何相加才能填满
        //dp数组下标的含义
        //dp数组
        //背包的重量 nums
        //背包的价值 nums
        //不可重复放入
        // 确定dp数组的定义和每个下标的含义
        // dp[] 为0~i下标填入背包空间j的最大价值,看是否等于11
        // 确定递推公式
        // dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
        // 确定遍历顺序
        // 从后往前
        // dp数组初始化
        // 都为0
        // 手动推导dp数组
        int sum = 0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        if(nums.length==1){
            return false;
        }
        if(sum%2==1){
            return false;
        }
        int target = sum/2;
        int[] dp = new int[target+1];
        
        //i为物品
        //j为空间
        for(int i=0;i<nums.length;i++){
            for(int j=target;j>=nums[i];j--){
                dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
                //若这个位置的dp[j]可以填满
                if(dp[j]==target){
                    return true;
                }
            }
        }
        return false;
    }
}

到了这里,关于动态规划day04(01背包问题)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法系列--动态规划--背包问题(1)--01背包介绍

    💕\\\"趁着年轻,做一些比较cool的事情\\\"💕 作者:Lvzi 文章主要内容:算法系列–动态规划–背包问题(1)–01背包介绍 大家好,今天为大家带来的是 算法系列--动态规划--背包问题(1)--01背包介绍 背包问题是动态规划中经典的一类问题,经常在笔试面试中出现,是非常 具有区分度 的题

    2024年04月16日
    浏览(37)
  • 算法学习17-动态规划01:背包问题

    提示:以下是本篇文章正文内容: 提示:这里对文章进行总结: 💕💕💕

    2024年04月27日
    浏览(33)
  • 【动态规划】01背包问题——算法设计与分析

    若超市允许顾客使用一个体积大小为13的背包,选择一件或多件商品带走,则如何选择可以使得收益最高? 商品 价格 体积 啤酒 24 10 汽水 2 3 饼干 9 4 面包 10 5 牛奶 9 4 0-1 Knapsack Problem 输入: quad - n n n 个商品组成集合 O O O ,每个商品有属性价格 p i p_i p i ​ 和体积 v i v_i v

    2024年02月04日
    浏览(52)
  • 第九章 动态规划part04(● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集 )

    ● 01背包问题,你该了解这些! ● 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://www.bilibili.com/video/BV1cg411g7Y6 1.确定dp数组以及下标的含义 i是物品,j是背包容量

    2024年01月16日
    浏览(37)
  • 算法分析与设计——动态规划求解01背包问题

    假设有四个物品,如下图,背包总容量为8,求背包装入哪些物品时累计的价值最多。 我们使用动态规划来解决这个问题,首先使用一个表格来模拟整个算法的过程。 表格中的信息表示 指定情况下能产生的最大价值 。例如, (4, 8)表示在背包容量为8的情况下,前四个物品的最

    2024年02月04日
    浏览(49)
  • 【Java实现】动态规划算法解决01背包问题

    1、问题描述: 一个旅行者有一个最多能装m公斤的背包,现在有n中物品,每件的重量分别是W1、W2、……、Wn,每件物品的价值分别为C1、C2、……、Cn, 需要将物品放入背包中,要怎么样放才能保证背包中物品的总价值最大? 2、动态规划算法的概述 1)动态规划(Dynamic Progra

    2023年04月09日
    浏览(36)
  • 算法套路十四——动态规划之背包问题:01背包、完全背包及各种变形

    如果对递归、记忆化搜索及动态规划的概念与关系不太理解,可以前往阅读算法套路十三——动态规划DP入门 背包DP介绍:https://oi-wiki.org/dp/knapsack/ 0-1背包:有n个物品,第i个物品的体积为w[i],价值为v[i],每个物品至多选一个, 求体积和不超过capacity时的最大价值和,其中i从

    2024年02月10日
    浏览(41)
  • C++算法初级11——01背包问题(动态规划2)

    辰辰采药 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时

    2024年02月02日
    浏览(32)
  • 【算法|动态规划 | 01背包问题No.2】AcWing 423. 采药

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成

    2024年02月06日
    浏览(34)
  • 算法基础复盘笔记Day09【动态规划】—— 背包问题

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2023年04月22日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包