算法系列--动态规划--背包问题(1)--01背包详解
💕"趁着年轻,做一些比较cool的事情"💕
作者:Mylvzi
文章主要内容:算法系列–动态规划–背包问题(1)–01背包详解
大家好,今天为大家带来的是
算法系列--动态规划--背包问题(1)--01背包详解
一.什么是背包问题
背包问题是动态规划中经典的一类问题,经常在笔试面试中出现,是非常具有区分度的题目
背包问题的种类很多,变式多,也就使得背包问题的难度一般都很高,而01背包问题属于其中最基础,可以当做思考模版的题目,下面就来讲解–01背包问题
前情提示:如果你没有动态规划的基础,还是尽量不要通过背包问题入门,先去做上几十到动态规划的题目再来学习背包问题
二.01背包问题
链接:
01背包问题

分析:
首先要明确这道题目一共有两问,第一问求的是在不超过背包限制的前提下,可以得到的最大价值
,第二问求的是在刚好装满背包的情况下,可以得到的最大价值
第一问:求这个背包至多能装多大价值的物品?
我们先来模拟一下背包问题的执行过程,其实就是从所有物品中选择合适的物品填入背包,来实现价值的最大化,在选物品时我们是可以任意选择的,这不就类似于在任意的子序列中,选出最大xxxx的问题么?
好了,相信大家也能分析到这里,说:这不就是一个简单的子序列问题么,这有啥难得,于是兴致勃勃的写下状态表示
dp[i]:表示在[1,i]之间的所有物品中,可以实现的最大价值物品的价值
(注:下标我们从1开始是因为这是dp问题常用的一种初始化dp表的方式)
但是我们在填i位置的值时,需要考虑此时背包容量对我们装填的影响(比如如果背包的容量很小,只有1,而我们i物品的体积是99,肯定无法装进去)
所以我们还需要一个状态来表示背包体积,也就是每走到一个物品都要保证符合容量大小,于是状态表示如下:
dp[i][j]:在[1,i]之间的所有物品中,体积不超过j,可以实现的最大价值物品的价值
我们可以验证一下这个状态表示能否返回最终的结果呢?可以,dp[n][V]就表示在所给定的n个物品中,体积不超过背包的最大体积V,选择可以实现最大价值的物品的价值
接下来就来推到状态转移方程:
状态转移方程一般就是根据最后一个位置的状态去讨论,在本题中,分类讨论的依据就是包不包括最后一个物品

注意:选nums[i]这种情况不是一定能实现的,需要满足此时的背包体积大于第i个物品的体积,也就是需要满足j - v[i] >= 0
返回值:dp[n][V]
以上就是第一问的详细分析过程
第二问:若背包恰好装满,求至多能装多大价值的物品?
相较于第一问多了体积的限制,必须要满足体积的前提下实现价值的最大化,但是大致的思路和第一问很像,只需要在第一问的基础上做出一些改变即可:
dp[i][j]:表示在[0,i]区间内的物品,在体积为j的前提下,可以实现的最大价值
状态转移方程

这里多了个限制条件dp[i - 1][j - v[i]] != -1,还是根据题目要求得来的,要考虑一种特殊情况,也就是在[0,i]区间内的物品根本无法组合成体积为j的情况(这也是会存在的),要想i位置存在价值,必须保证i-1位置刚好能够实现j-v[i]的体积
初始化相较于第一问也有所不同,具体来说需要把dp表的第一行初始化为-1(除了dp[0][0]),第一行代表不选择任何物品,也就无法构成满足j体积这个条件,我们将其设置为-1
之所以设置为-1是为了和dp[0][0] = 0这种情况作区分
代码:
import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {static int N = 1010;public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt(), V = in.nextInt();// 获取物品数目和背包体积// 处理第一问int[] v = new int[N],w = new int[N];// 存储物品的体积和价值for(int i = 1; i <= n; i++) {// 输入数值v[i] = in.nextInt(); w[i] = in.nextInt();}int[][] dp = new int[N][N];for(int i = 1; i <= n; i++) {for(int j = 1; j <= V; j++) {dp[i][j] = dp[i - 1][j];if(j - v[i] >= 0) dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - v[i]] + w[i]);}}System.out.println(dp[n][V]);// 处理第二问dp = new int[N][N];for(int j = 1; j <= V; j++) {// 初始化dp[0][j] = -1;}for(int i = 1; i <= n; i++) {for(int j = 1; j <= V; j++) {dp[i][j] = dp[i - 1][j];if(j - v[i] >= 0 && dp[i - 1][j - v[i]] != -1)dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - v[i]] + w[i]);}}System.out.println(dp[n][V] == -1 ? 0 : dp[n][V]);}
}
上述解法的空间复杂度是很高的,我们开辟的dp表是一个N*N的,下面介绍使用滚动数组实现空间优化

空间优化之后的代码:
import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {static int N = 1010;public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt(), V = in.nextInt();// 获取物品数目和背包体积// 处理第一问int[] v = new int[N],w = new int[N];// 存储物品的体积和价值for(int i = 1; i <= n; i++) {// 输入数值v[i] = in.nextInt(); w[i] = in.nextInt();}int[] dp = new int[N];for(int i = 1; i <= n; i++) for(int j = V; j >= v[i]; j--) dp[j] = Math.max(dp[j],dp[j - v[i]] + w[i]);System.out.println(dp[V]);// 处理第二问dp = new int[N];for(int j = 1; j <= V; j++) dp[j] = -1;// 初始化for(int i = 1; i <= n; i++) for(int j = V; j >= v[i]; j--) if(j - v[i] >= 0 && dp[j - v[i]] != -1)dp[j] = Math.max(dp[j],dp[j - v[i]] + w[i]);System.out.println(dp[V] == -1 ? 0 : dp[V]);}
}
总结:本文的核心要点
- 什么是背包问题
- 01背包问题详解
- 背包问题的空间优化(滚动数组)
相关文章:
算法系列--动态规划--背包问题(1)--01背包详解
💕"趁着年轻,做一些比较cool的事情"💕 作者:Mylvzi 文章主要内容:算法系列–动态规划–背包问题(1)–01背包详解 大家好,今天为大家带来的是算法系列--动态规划--背包问题(1)--01背包详解 一.什么是背包问题 背包问题…...
【KB】通过Karabiner-Elements实现 optionTAB与 commandTAB 对调/映射 win 的 altTAB 习惯
学习Karabiner-Elements的第一个 demo,因为推荐的例子中过多参数,这是一个简化版。 需求:对调 optionTAB与 commandTAB,然后安装 altTAB 软件,恢复win切换任务的使用习惯。 {"description": "Change ta…...
nvm node包管理工具
下载地址:版本 1.1.9 CoreyButler/NVM-Windows (github.com) 使用nvm -v 检查安装是否成功。 常用命令 # 安装nodjs版本 nvm install 10.16.3nvm install 14.15.4# 切换,使用nodejs nvm use 10.16.3 ## nvm use 报错,1).使用管理员打开…...
程序员如何兼职赚小钱?
程序员由于有技术和手艺其实兼职赚钱的路子还是挺多的,只要你有足够的时间。 1. 做外包 这是比较传统的方式,甲方在一些众包平台上发布开发任务,你可以抢这个任务,但是价格都比较便宜。 任务比较多的平台: 猪八戒、一品威客、开…...
奥比中光深度相机(一):环境配置
文章目录 奥比中光深度相机(一):环境配置简介电脑环境SDK配置步骤安装环境依赖填写路径,点击Configure选择Visual studio点击Generate完成基于Python的SDK配置方法一:使用Cmake直接打开方法二:通过源文件打…...
API网关-Apisix路由配置教程(数据编辑器方式)
文章目录 前言一、端口修改1. apisix 端口修改2. dashboard 端口修改3. 登录密码修改 二、常用插件介绍1. 常用转换插件1.1 proxy-rewrite插件1.1.1 属性字段1.1.2 配置示例 2. 常用认证插件2.1 key-auth插件2.1.1 消费者端字段2.1.2 路由端字段2.1.3 配置示例 2.2 basic-auth插…...
Transformer的前世今生 day10(Transformer编码器
前情提要 ResNet(残差网络) 由于我们加更多层,更复杂的模型并不总会改进精度,可能会让模型与真实值越来越远,如下: 我们想要实现,加上一个层把并不会让模型变复杂,即没有它也没关系…...
【c++模板】泛型编程(你真的懂模版特化、分离编译和非类型参数吗)
🪐🪐🪐欢迎来到程序员餐厅💫💫💫 今日主菜:模板 主厨:邪王真眼 主厨的主页:Chef‘s blog 所属专栏:c大冒险 总有光环在陨落,总有新星在…...
力扣1----10(更新)
1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按…...
[Qt] QString::fromLocal8Bit 的使用误区
QString::fromLocal8Bit 是一个平台相关的函数。默认情况下在 Windows 下 就是 gbk 转 utf-8 ,在 Linux就应该是无事发生。因为Linux平台默认的编码方式就是 utf-8 可以通过 void QTextCodec::setCodecForLocale(QTextCodec *c)来修改 Qt默认的编码方式。如下 第一输出乱码的…...
什么是RabbitMQ的死信队列
RabbitMQ的死信队列(Dead Letter Queue,简称DLQ)是一种用于处理消息失败或无法路由的消息的机制。它允许将无法被正常消费的消息重新路由到另一个队列,以便稍后进行进一步处理、分析或排查问题。 当消息对立里面的消息出现以下几…...
力扣面试150 删除有序数组中的重复项 双指针
Problem: 26. 删除有序数组中的重复项 思路 👩🏫 三叶题解 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public int removeDuplicates(int[] nums) {int j 0, n nums.length;for(int i 0;…...
政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(二)—— 深度神经网络
政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! 概述 深度神经网络(Deep Neural Network…...
【链表】Leetcode 138. 随机链表的复制【中等】
随机链表的复制 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点…...
【计算机网络教程】(第六版)第2章课后习题答案
第二章 2-012-022-032-042-062-072-082-092-102-112-122-132-142-152-16 2-01 物理层要解决哪些问题?物理层的主要特点是什么? 答: 物理层要解决的主要问题: (1)物理层要尽可能地屏蔽掉物理设备和传输媒体&…...
抖音电商“达人客服”产品上线啦!超多作者邀你一起“321上客服”!
有问题别自己克服,来抖音电商找“达人客服” 当代年轻人购物,正在从机智省变成理智购。越来越多的人在达人直播间购物,看重的不止是优惠力度,还有服务保障。 为了帮助达人更好地服务用户,抖音电商上线了「达人客服」…...
华为防火墙二层墙(VAN/SVI/单臂路由)
二层墙只能做地址池形式的NAT。 交换机安全策略防火墙二层墙 路由器安全策略防火墙三层墙 交换机的光口是不能直接插线的,光模块,包括进和出 长距离:单模 短距离:多模 防火墙自身的ping流量需要单独配置...
idea使用git笔记
1.创建分支和切换分支 创建分支 切换分支 2.把新创建的分支提交到远程服务器上(注:如果没有提交的,随便找个文件修改再提交) (1)切换到要提交的分支,add (2)commit (3)push 3.在自己分支修改代码及提交到自己的远…...
智慧校园数据可视化有什么好处?怎么推进数字化校园方案?
在当今数字化时代,越来越多学校开始实施智慧校园计划,旨在为学生和教师提供更高效、便捷的学习和教学环境。智慧校园运用互联网、大数据、人工智能等技术,对校园内各信息进行收集、整合、分析和应用,实现教学、管理、服务等多方面…...
如何利用python编写函数fn(a,n)求数列和
1 问题 编写函数fn(a,n) 求aaaaaa⋯aa⋯aa(n个a)之和,fn须返回的是数列和,输入正整数a和n的值(两个值都不超过9),并输出fn(a,n)的结果值。 2 方法 运用def 定义函数和for 循环递归方法: 先定义fn(a,n)函数;…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
用js实现常见排序算法
以下是几种常见排序算法的 JS实现,包括选择排序、冒泡排序、插入排序、快速排序和归并排序,以及每种算法的特点和复杂度分析 1. 选择排序(Selection Sort) 核心思想:每次从未排序部分选择最小元素,与未排…...

