代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集

news2025/1/22 9:14:28

背包问题

说到背包问题大家都会想到使用动规的方式来求解,那么为什么用动规呢,dp数组代表什么呢?初始化是什么,遍历方式又是什么,这篇文章笔者将详细讲解背包问题的经典例题0-1背包问题和完全背包问题的解题方式,希望能帮助到大家

1.暴力方式

有人一提到背包问题就只会使用动态规划来做,那么背包问题假如让你使用暴力求解该如何解决呢?我们以0-1背包为例,每个物品是不是只有两种状态?放或者不放,我们可以遍历所有方式,使用回溯来解决问题.

0-1背包问题解决方式(二维数组)

动规五部曲

1.明白dp数组的含义

此处dp[i][j]表示的就是从[0,i]个物品中任选,用容量为j的背包能装的最大价值.

2.数组的初始化和递推公式的理解

递推公式:

不放物品:其实就是延续上一层的最大价值即可

dp[i][j] = dp[i-1][j]

放入物品:取上一层的数据或者放入这一层的物品加上剩下的容量的最大价值,两者之间取最大值即可

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

初始化数组:

首先从定义出发dp[i][0]一定得初始化为0,0容量的背包装不了东西

由于每一行的数据都是由上一行推导产生的,所以第一行的数据我们也要进行初始化,i从weight[0]开始初始化就行,因为背包的容量的大于等于第一个物品的容量才能装的进去它.

3.遍历顺序的理解

这里我们可以感受一下先遍历背包和先遍历物品的区别,其实都可以达到我们的效果,但是先

遍历物品更好理解

那么为什么两种遍历方式都可以解决问题呢?

如下图所示,因为无论是哪种遍历方式,我们的dp[i][j]都是由左上角的元素推导出来的,所以无所谓用哪种遍历顺序都可以.

 for(int i = 1;i<goods;i++){
            for (int j = 1; j <= bagSize; j++) {
                if(j<weight[i]){
                    dp[i][j] = dp[i-1][j];
                }else{
                    dp[i][j] = Math.max(dp[i-1][j],value[i]+dp[i-1][j-weight[i]]);
                }
            }
        }

4.打印数组进行查看

0-1背包示例代码

    public static void func1(int[] weight, int[] value, int bagSize){

        //初始化dp数组
        int goods = weight.length;
        int[][] dp = new  int[goods][bagSize+1];
        for (int i = weight[0]; i <=bagSize; i++) {
            dp[0][i] = value[0];
        }
        for(int i = 1;i<goods;i++){
            for (int j = 1; j <= bagSize; j++) {
                if(j<weight[i]){
                    dp[i][j] = dp[i-1][j];
                }else{
                    dp[i][j] = Math.max(dp[i-1][j],value[i]+dp[i-1][j-weight[i]]);
                }
            }
        }
        for (int i = 0; i < goods; i++) {
            for (int j = 0; j <=bagSize; j++) {
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }




    }












//main方法中代码
        int[] value = {15,20,30};
        int[] weight = {1,3,4};
        int bagSize = 4;
        func1(weight,value,bagSize);

0-1背包问题解决方式(一维数组)

1.明白dp数组的含义

这里使用一维数组滚动覆盖来代替二维数组,就类似于将一个矩阵压成了一行

我们先回顾一下二维数组的含义dp[i][j]:从[0,i]的物品中,背包容量为j能装的最大价值

这里的dp[j]就是背包容量为j能装的最大价值

其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

2.递推公式的理解

我们知道dp[j]可以通过dp[j - weight[i]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。

然后递推公式由两个选择,一个是上一层的值和本层的物品价值加上剩余空间价值的较大值

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

3.数组的初始化

根据上面的递推公式,我们知道初始化一定不能初始化成一个大值,因为可能太大了而导致后面的dp[j-weight[i]]+value[i]无法覆盖他的值,所以我们初始化为0即可

4.遍历顺序的理解

我们先上代码,后讲解原因

我们发现这里的背包遍历是从后向前遍历的,为什么呢,举个例子

如果是从前向后遍历

那么dp[1] = dp[1-1]+value[0] = 15

dp[2] = dp[2-1] +value[0]= 30

这不符合我们0-1背包的每件物品只能使用一次的逻辑,因为这里物品1被放入了两次

而我们从后向前遍历就可以避免这个问题

dp[4] = dp[3]+value[0];

dp[3] = dp[2]+value[0];

...这里就不会存在重复计算问题

为什么上面二维数组的遍历不需要倒序呢?

因为二维数组的dp[i][j]是由上一层的元素推导出来,不会影响本层的元素

以为数组的遍历顺序只能是先遍历物品,再遍历背包!!!

我们还是举个例子来说明(一维数组,我们以二维数组的形式画出来),我们就会发现,如果用容量来遍历物品的话,其实就是每个容量的背包只取得了一个物品,与答案相悖

for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

    }
}

5.打印数组进行查看

示例代码 

   public static void func2(int[] weight, int[] value, int bagWeight) {
        int wLen = weight.length;
        //定义dp数组:dp[j]表示背包容量为j时,能获得的最大价值
        int[] dp = new int[bagWeight + 1];
        //遍历顺序:先遍历物品,再遍历背包容量
        for (int i = 0; i < wLen; i++) {
            for (int j = bagWeight; j >= weight[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
            }
        }
        //打印dp数组
        for (int j = 0; j <= bagWeight; j++) {
            System.out.print(dp[j] + " ");
        }
    }
}

LeetCode T416 等和子集问题

题目链接:416. 分割等和子集 - 力扣(LeetCode)

题目思路:

利用上述思路,这里的背包容量是数组之和的一半,重量和价值数组都等于源数组,上面给出一定的剪枝,假如出现奇数就直接返回false,出现只有一个元素也直接返回false,下面我给出解题代码.

题目代码:

class Solution {
    public boolean canPartition(int[] nums) {
        if(nums.length == 1){
            return false;
        }
        int sum = 0;
        for(int i:nums){
            sum += i;
        }
        if(sum % 2 == 1){
            return false;
        }
        int bagSize = sum/2;
        int[] dp = new int[bagSize+1];
        //初始化均为0
        for(int i = 0;i<nums.length;i++){
            for(int j = bagSize;j>=nums[i];j--){
                dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
        }
        if(dp[bagSize] == bagSize){
            return true;
        }
       return false;

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1165227.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++之队列queue

1.知识百科 队列是一种特殊的线性表&#xff0c;特殊之处在于它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#xff09;进行插入操作&#xff0c;和栈一样&#xff0c;队列是一种操作受限制的线性表。进行插入操作的…

Idea - Apifox Helper 插件的安装、配置令牌、导出

第一步&#xff1a;先安装插件&#xff08;其他EASY API 、Api docx同理&#xff09; 等待安装完毕 第二步&#xff1a; 导出你想导出的API 提示我们没有找到配置文件&#xff0c;需要到设置里面设置Personal Access Token 第三步&#xff1a;到设置里面设置Personal Access T…

AI:50-基于深度学习的柑橘类水果分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

城市内涝解决方案:实时监测,提前预警,让城市更安全

城市内涝积水问题是指城市地区在短时间内遭遇强降雨后&#xff0c;地面积水过多&#xff0c;导致城市交通堵塞、居民生活不便、财产损失等问题。近年来&#xff0c;随着全球气候变化和城市化进程的加速&#xff0c;城市内涝积水问题越来越突出&#xff0c;成为城市发展中的一大…

C++之初始化列表详细剖析

一、初始化列表定义 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始值或表达式。 class Date { public:Date(int year, int month, int day): _year(year), _month(mont…

tauri 访问静态资源,响应头为Content-Type:‘text/html‘

现象 报错&#xff1a; Error: THREE.FBXLoader: Unknown format. at FBXLoader.parse (index-f8291142.js:22050:15) at Object.onLoad (index-f8291142.js:22033:22) at index-f8291142.js:19769:20 使用threejs 加载fbx模型文件时&#xff0c;返回头中Content-…

《C++ Primer》第6章 函数(一)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 6.1 函数基础&#xff08;P182&#xff09; 典型的函数定义包括&#xff1a;返回类型&#xff08; return type &#xff09;、函数名字、0 个或多个形参&#xff08; parameter &#xff09;组成的列表、函…

使用HttpClient库的爬虫程序

使用HttpClient库的爬虫程序&#xff0c;该爬虫使用C#来抓取内容。 using System; using System.Net.Http; using System.Threading.Tasks; ​ namespace CrawlerProgram {class Program{static void Main(string[] args){// 创建HttpClient对象using (HttpClient client new…

数据结构 - 顺序表ArrayList

目录 实现一个通用的顺序表 总结 包装类 装箱 / 装包 和 拆箱 / 拆包 ArrayList 与 顺序表 ArrayList基础功能演示 add 和 addAll &#xff0c;添加元素功能 ArrayList的扩容机制 来看一下&#xff0c;下面的代码是否存在缺陷 模拟实现 ArrayList add 功能 add ind…

Linux多线程服务端编程:使用muduo C++网络库 学习笔记 第七章 muduo编程示例(上)

本章将介绍如何用muduo网络库完成常见的TCP网络编程任务。内容如下&#xff1a; 1.[UNP]中的五个简单协议&#xff0c;包括echo、daytime、time、discard、chargen等。 2.文件传输&#xff0c;示范非阻塞TCP网络程序中如何完整地发送数据。 3.Boost.Asio中的示例&#xff0c;…

新手学习两种不同的存储方式(不喜勿喷)

localStorage.setItem(sid,res.info.id)console.log(sid,res.info.id)sessionStorage.setItem(uid,res.info.id) sid和uid&#xff0c;也可以写其他的只来替代&#xff1b;而res.info.id是接口的数据可替换成自己的 一次性传的id值刷新页面就没有 永久性传的id 这是Javascript…

Linux——切换CUDA版本

一、查看本地cuda版本 cd /usr/local/ ls当前cuda为软连接&#xff0c;指向指定的cuda版本 stat cuda # 查看当前cuda状态信息二、切换CUDA版本 # 删除原有软连接 sudo rm -rf /usr/local/cuda # 建立需要切换的cuda软连接版本 sudo ln -s /usr/local/cuda-**.* /usr/l…

【GitLab、GitLab Runner、Docker】GitLab CI/CD 应用

安装Gitlab开源版 官方文档-安装Gitlab 使用Docker安装 sudo docker run --detach \--hostname gitlab.example.com \--env GITLAB_OMNIBUS_CONFIG"external_url http://${ip}:9999/; gitlab_rails[gitlab_shell_ssh_port] 8822;" \--publish 443:443 --publish 99…

Circos图绘制

Circos图其实是一个用途非常广泛的图形&#xff0c;可以用于表征基本上任何类型的数据&#xff0c;包括把我们常见的散点图、折线图和柱状图等都可以整合到Circos当中。特别是&#xff0c;Circos尤其适合用来描述生物信息学和基因组学的数据。 1.绘制Circos图 目前绘制Circos图…

单元测试一(理论)-云计算2023.11-云南农业大学

实验《 ECS数据管理实践-备份与恢复》 https://developer.aliyun.com/adc/scenario/7ad13e326c924d07a1ddb4e88cb26ce4 数据盘挂载到 /alidata&#xff0c;alidata改为自己姓名全拼&#xff0c;数据盘上创建文件test.txt&#xff0c;改为test接自己姓名全拼.txt&#xff0c;快…

根据Word模板,使用POI生成文档

突然想起来有个小作业&#xff1a;需要根据提供的Word模板填充数据。这里使用POI写了一个小demo验证下。 测试用模板&#xff1a; 执行结果 1.引入依赖坐标 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId&…

07、如何取出对象数组里的固定 key 值来拼成一个对象(以及对象与数组之间的转化)

1、数据情况&#xff1a; 其一、从后端拿到的数据为&#xff1a; let arr [1, 3, 7, 24] 其二、目标数据为(即&#xff1a;后台需要下发的数据)&#xff1a; {vlan_1: 1, vlan_3: 1, vlan_7: 1, vlan_24: 1} 2、操作过程&#xff1a; 其一、定义一个动态的 key 值来满足…

基于nodejs+vue客户管理管理系统

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

JAVA代码审计-cms综合篇

前言 JEECGv3.8。下载地址&#xff1a;GitHub - jeecgboot/jeecg at v3.8 java代码审计第一步&#xff1a;查看web.xml 一个重要的servlet&#xff1a;DispatcherServlet&#xff0c; <servlet><description>spring mvc servlet</description><servle…

MYSQL体系结构总结

&#xff08;笔记整理自b站马士兵教育课程&#xff09; MYSQL总体分为服务层和存储引擎层。 一、服务层 功能&#xff1a; 1、连接&#xff1a;管理连接&#xff0c;权限验证。 2、解析器&#xff1a;词法分析&#xff0c;语法分析。 3、优化器&#xff1a;执行计划生成…