动态规划:09 0-1背包理论基础I

news2024/12/23 19:04:08

动态规划:09 0-1背包理论基础I

背包问题概述

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

如果这几种背包,分不清,就看下图

在这里插入图片描述

leetcode上连多重背包的题目都没有,这就告诉我们,01背包和完全背包就够用了。

而完全背包又是01背包稍作变化而来,即:完全背包的物品数量是无限的。

所以背包问题的理论基础重中之重是01背包,一定要理解透!

leetcode上没有纯01背包的问题,都是01背包应用方面的题目,也就是需要转化为01背包问题。

所以后面先通过纯01背包问题,把01背包原理理解清楚,后续再写eetcode题目的时候,重点就是讲解如何转化为01背包问题了

01背包

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

这是标准的背包问题,以至于很多同学看了这个自然就会想到背包,甚至都不知道暴力的解法应该怎么解了。

这样其实是没有从底向上去思考,而是习惯性想到了背包,那么暴力的解法应该是怎么样的呢?

每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是 o ( 2 n ) o(2^n) o(2n),这里的n表示物品数量。

所以暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!

在下面的讲解中,我举一个例子:

背包最大重量为4。

物品为:

重量价值
物品0115
物品1320
物品2430

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

以下讲解和图示中出现的数字都是以这个例子为例。

二维dp数组01背包 五部曲

  1. 确定dp数组含义:编号为0-i的物品,任取放入容量为j的背包,最大价值为dp[i][j]

    对于背包问题,有一种写法, 是使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少

    在这里插入图片描述

    要时刻记着这个dp数组的含义,下面的一些步骤都围绕这dp数组的含义进行的,如果哪里看懵了,就来回顾一下i代表什么,j又代表什么。

  2. 确定递归公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[j])

    再回顾一下dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。那么可以有两个方向推出来dp[i][j],

    不放物品i,最大价值为:dp[i - 1][j]

    放物品i:dp[i - 1][j - weight[i]] + value[j]

  3. dp数组初始化:dp[0][j] dp[i][0]

    关于初始化,一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱

    首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。

    在看其他情况。

    状态转移方程 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。

    dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。

    那么很明显当 j < weight[0]的时候,dp[0][j] 应该是 0,因为背包容量比编号0的物品重量还小。

    当j >= weight[0]时,dp[0][j] 应该是value[0],因为背包容量放足够放编号0物品。

    物品i\容量j01234
    00value[0](如果能放的话)value[0](如果能放的话)value[0](如果能放的话)value[0](如果能放的话)
    10max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[j])
    20
    30
    40

    dp[0][j] 和 dp[i][0] 都已经初始化了,那么其他下标应该初始化多少呢?

    其实从递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 可以看出dp[i][j] 是由左上方数值推导出来了,那么 其他下标初始为什么数值都可以,因为都会被覆盖。

    初始-1,初始-2,初始100,都可以!

    但只不过一开始就统一把dp数组统一初始为0,更方便一些。

  4. 遍历顺序:二维数组的话,先遍历背包或先遍历物品都可以

    dp[i][j] = max(dp[i - 1]\j], dp[i - 1][j - weight[i]] + value[i]); 递归公式中可以看出dp[i][j]是靠dp[i-1][j]和dp[i - 1][j - weight[i]]推导出来的。

    dp[i-1][j]和dp[i - 1][j - weight[i]] 都在dp[i][j]的左上角方向(包括正上方向)

  5. debug:打印dp数组

题目与代码

题目

输入

第一行包含两个正整数,第一个整数 M 代表研究材料的种类,第二个正整数 N,代表小明的行李空间。

第二行包含 M 个正整数,代表每种研究材料的所占空间。

第三行包含 M 个正整数,代表每种研究材料的价值。

输出

输出一个整数,代表小明能够携带的研究材料的最大价值。

样例输入
6 1
2 2 3 1 5 2
2 3 1 5 4 3
样例输出
5

代码

import java.util.Arrays;
import java.util.Scanner;

public class Main{
    public static void main(String... args) {
        Scanner scanner = new Scanner(System.in);
        int M;
        int bagSize;
        M = scanner.nextInt();
        bagSize = scanner.nextInt();

//        System.out.println("M:" + M +" bagSize:" + bagSize);

        int[] weight = new int[M];
        int[] value = new int[M];
        for(int i = 0; i < M; i++) {
            weight[i] = scanner.nextInt();
        }
//        System.out.println("weight数组:" + Arrays.toString(weight));

        for(int i = 0; i < M; i++) {
            value[i] = scanner.nextInt();
        }
//        System.out.println("value数组:" + Arrays.toString(value));

        int res = testWeightBagProblem(weight, value, bagSize);
        System.out.println(res);
    }

    public static int testWeightBagProblem(int[] weight, int[] value, int bagSize) {
        int[][] dp = new int[weight.length][bagSize + 1];
        //初始化dp数组,第一列默认值就是0
        for(int j = weight[0]; j <= bagSize; j++) {
            dp[0][j] = value[0];
        }

        for(int i = 1; i < weight.length; 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], (dp[i - 1][j - weight[i]] + value[i]));
                }
            }
        }

//        testAndVerify(dp);

        return dp[weight.length - 1][bagSize];
    }

    public static void testAndVerify(int[][] dp){
        //验证dp数组
        System.out.println(Arrays.deepToString(dp));
    }
}

总结

这里其实可以发现最简单的是推导公式了,推导公式估计看一遍就记下来了,但难就难在如何初始化和遍历顺序上

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

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

相关文章

【MATLAB-Retinex图像增强算法的去雾技术】

续&#xff1a;【MATLAB-基于直方图优化的图像去雾技术】 【MATLAB-Retinex图像增强算法的去雾技术】 1 原图2 MATLAB实现代码3 结果图示 参考书籍&#xff1a;计算机视觉与深度学习实战:以MATLAB、Python为工具&#xff0c; 主编&#xff1a;刘衍琦, 詹福宇&#xff0c; 王德建…

C++入门篇(3)---引用

1.引用 你有没有被人起过外号?比如身边的朋友,喊他的时候不会叫他的全名,像我很好的朋友,我一般都喜欢叫他"阿威",而不会去称呼全名.我叫他"阿威",他还是他没有什么问题. 这里新登场的引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&am…

学会这招,轻松掌握学校教学质量!

在教育领域&#xff0c;教育管理者和学校管理员需要确保教学过程的质量和效率。在线巡课系统是一种强大的工具&#xff0c;可以帮助他们实时监测教学过程、教师绩效和学生学习情况。 在线巡课系统结合了技术和教育的最佳实践&#xff0c;为学校提供了数据驱动的决策支持和资源管…

SGPT: GPT Sentence Embeddings for Semantic Search

简介 语义搜索分为两个部分&#xff1a; 1.搜索和query 相关的topk文档。 2.理解文档和query后面隐藏的语义信息&#xff0c;而不是字面含义。 这篇论文提出了SGPT模型&#xff0c;只用decoder-only的transformer来进行语义搜索和sentence向量的提取。 1.SGPT-BE&#xff1a;来…

有什么手机软件能分离人声和音乐?

很多人在制作混剪视频&#xff0c;需要二次创作的时候&#xff0c;就经常会把人声分离、背景音乐伴奏提取出来&#xff0c;然后重新加入自己的创意跟想法。下面就一起来看看如何用手机软件分离人声和音乐的吧&#xff01; 音分轨 一款可以分离人声和背景音乐的手机软件&#x…

我才35岁就要面临“人到中年不服老不行”?大龄测试的救赎之路就在其中!

人说“三十而立”&#xff0c;可对于测试来说是“三十而秃”&#xff0c;除了日常秃头&#xff0c;而立之年的测试们的开始焦虑自己的职业未来。 自2017年华为传出“清理35岁以上员工”以来&#xff0c;各企业关于“劝退 35 岁以上员工”、“招聘限 35 岁以下”的传闻此起彼伏…

前端数据可视化之【Echarts介绍】

目录 &#x1f31f;前言&#x1f31f;丰富的可视化类型&#x1f31f;多种数据格式无需转换直接使用&#x1f31f;移动端优化&#x1f31f;多渲染方案&#xff0c;跨平台使用&#xff01;&#x1f31f;写在最后 &#x1f31f;前言 ECharts开源来自百度商业前端数据可视化团队&a…

数据类型转换

一.应用函数或者方法 1.cast 函数 cast&#xff08;变量 as 数据类型&#xff09; 语义&#xff1a;将变量转为这个类型 2. 变量 ::数据类型 将变量转化为xx类型 3.to_date函数 to_date&#xff08;字符串&#xff0c;format&#xff09; 语义&#xff1a;转换成日期类…

运用精益管理思想提升MES管理系统建设水平

随着制造业的不断发展&#xff0c;MES生产管理系统已经成为了企业生产过程中不可或缺的一部分。而在MES管理系统建设过程中&#xff0c;精益管理的思想也越来越受到重视。本文将探讨如何运用精益管理的思想&#xff0c;提高MES系统的建设水平&#xff0c;以更好地服务于企业的生…

故障诊断实验台 | PT600电机电气故障实验台

很多同学因为实验数据而被困扰&#xff0c;目前数据来源有3方面&#xff0c;公开实验数据集、校企合作项目实际数据、自制实验台数据。 公开实验数据集被用烂了&#xff0c;容易被审稿人质疑&#xff1b; 校企合作项目实际数据缺少故障数据&#xff0c;数据需保密&#xff0c;…

SDK和API区别

B站视频&#xff1a;https://www.bilibili.com/video/BV1dA411K7Ps/?spm_id_from333.337.search-card.all.click&vd_source85701dd8aeeae2aaac0299ea796f19bb 假设你在开发一款移动端兽医诊所应用 Lets say youre developing a mobile app for a veterinarian clinic 想法…

vue3怎么创建项目

1、先安装node.js 自行去node.js官网下载 2、创建一个文件夹 终端打开命令 3、执行命令 vue create 项目名称&#xff08;必须是英文开头&#xff0c;可以英文数字&#xff09; 4、选择Manually select features(自定义配置) 5、选择Router(后面要使用,也可以先不安装&am…

Sanic​——Python函数变成API的神器

今天给大家介绍一个超好用的框架&#xff0c;迅速将Python函数变成API&#xff0c;它就是最近越来越火的异步Web框架Sanic。 1. Sanic简介 Sanic 是 Python3.7 Web 服务器和 Web 框架&#xff0c;旨在提高性能。它允许使用 Python3.5 中添加的async/await语法&#xff0c;这使…

GPT4应用讲解,如何获取ChatGPT账号

参加每人均可获得1个独立可永久使用的ChatGPT账号&#xff0c;并提供不用fanqiang使用的方法。 前言 GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。例如在科研编程、绘图领域&#xff1a; 1、编程建议和示例代码: 无论你…

GFS分布式文件系统实验

GFS概念 Gluster 是一个开源的分布式文件系统 它是一个C/S架构 由存储服务器、客户端以及NFS/Samba存储网关组成 没有元数据服务器组件&#xff0c;这有助于提升整个系统的性能&#xff0c;可靠性和稳定性 文件系统定义 负责实现数据存储方式&#xff0c;以什么格式保存在…

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目 如图所示 我导入了一个git项目后&#xff0c;菜单栏出现了一个git按钮 找不到 导入git项目的按钮了 方式1、 通过idea设置 打开全局设置 如下图 把git先改为none&#xff0c;保存 保存后就可以看到 VCS按钮 导入…

程序员架构修炼:架构设计概要,业务、应用、技术、数据架构

作为一个程序员&#xff0c;了解架构设计是非常重要的&#xff0c;它能够帮助你更好地理解如何构建大型软件系统&#xff0c;并能够满足用户的需求。在架构设计中&#xff0c;通常会涉及到四种不同类型的架构&#xff1a;业务架构、应用架构、技术架构和数据架构。 1、业务架构…

鸿蒙初体验

下载与安装DevEco Studio 在HarmonyOS应用开发学习之前&#xff0c;需要进行一些准备工作&#xff0c;首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网&#xff0c;单击“立即下载”进入下载页面。 DevEco Studio提供了Windows版本和…

迅雷下载宝-openwrt-kodexplorer

下载仓库 雾渺/KODExplorer - Gitee.com 下载后解压上传文件/mnt/mmcblk0/kodexplorer ip:8080访问

NFTScan | 10.09~10.15 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2023.10.09~ 2023.10.15 NFT 热点资讯 01/ DeLabs&#xff1a;所有 DeGods 已重置回 Season1&#xff0c;用户可于本周将 y00ts 免费迁移至以太坊 10 月 9 日&#xff0c;DeGods & y…