动态规划算法之背包问题详细解读(附带Java代码解读)
动态规划中的背包问题(Knapsack Problem)是经典问题之一,通常用来解决选择一组物品放入背包使得背包的价值最大化的问题。根据问题条件的不同,背包问题有很多种变体,如0-1背包问题、完全背包问题、多重背包问题等。这里,我们详细介绍最经典的0-1背包问题,并提供代码的详细解读。
1. 0-1背包问题简介
在0-1背包问题中,有一个容量为 C
的背包和 n
件物品。每件物品有两个属性:重量 w[i]
和 价值 v[i]
。目标是选择若干件物品放入背包,使得总重量不超过 C
,并且背包中物品的总价值最大化。
问题的约束:
- 每件物品要么选择(放入背包),要么不选择,因此称为 0-1 背包问题。
- 背包的总重量不能超过
C
。 - 要最大化背包中物品的总价值。
2. 动态规划的思路
动态规划适用于背包问题,因为它具有最优子结构和重叠子问题的性质。解决这个问题的核心在于:针对每一个物品,都有两种选择——要么放进背包,要么不放进背包。
状态定义
定义 dp[i][j]
表示前 i
件物品放入容量为 j
的背包时所能获得的最大总价值。
状态转移方程
对于每件物品 i
:
- 如果不将第
i
件物品放入背包,则最大价值就是dp[i-1][j]
,即前i-1
件物品的最大价值。 - 如果将第
i
件物品放入背包,则最大价值为dp[i-1][j-w[i]] + v[i]
,即前i-1
件物品在剩余容量j-w[i]
时的最大价值加上当前物品的价值v[i]
。
综合起来,状态转移方程为:
dp[i][j]=max(dp[i−1][j],dp[i−1][j−w[i]]+v[i])
初始条件
当背包容量为0时,无论选哪件物品,最大价值都是0,即 dp[i][0] = 0
。
3. Java代码实现
public class Knapsack {public static void main(String[] args) {// 定义物品的重量和价值int[] weights = {2, 3, 4, 5}; // 每个物品的重量int[] values = {3, 4, 5, 6}; // 每个物品的价值int capacity = 8; // 背包容量int n = weights.length; // 物品数量// 计算并输出背包的最大价值System.out.println("Maximum value in Knapsack = " + knapsack(weights, values, n, capacity));}// 动态规划方法解决0-1背包问题public static int knapsack(int[] weights, int[] values, int n, int capacity) {// 定义DP数组:dp[i][j] 表示前 i 件物品在容量为 j 时的最大价值int[][] dp = new int[n + 1][capacity + 1];// 填充DP表for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {if (weights[i - 1] <= j) { // 当前物品可以放入背包dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);} else { // 当前物品无法放入背包dp[i][j] = dp[i - 1][j];}}}// 返回最后一个格子的值,即最大价值return dp[n][capacity];}
}
4. 详细解释代码
4.1 输入和输出
在 main
方法中,定义了物品的重量数组 weights[]
、价值数组 values[]
,以及背包的总容量 capacity
和物品数量 n
。然后调用 knapsack()
方法来计算背包中可以获得的最大价值。
4.2 knapsack()
函数详解
public static int knapsack(int[] weights, int[] values, int n, int capacity) {// 定义DP数组:dp[i][j] 表示前 i 件物品在容量为 j 时的最大价值int[][] dp = new int[n + 1][capacity + 1];
首先,定义了二维数组 dp[][]
,其中 dp[i][j]
表示前 i
件物品在背包容量为 j
时能够获得的最大总价值。数组的大小为 [n+1][capacity+1]
,因为我们需要处理物品数量从0到n、容量从0到capacity的所有情况。
4.3 初始化和状态转移
for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {if (weights[i - 1] <= j) {dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);} else {dp[i][j] = dp[i - 1][j];}}
}
接下来,用两个嵌套的 for
循环遍历物品和背包容量,进行状态转移:
- 外层循环
i
遍历每一件物品。 - 内层循环
j
遍历背包的每个可能容量。
对于每个物品 i
:
- 如果该物品的重量
weights[i-1]
小于或等于当前容量j
,可以选择放入背包或不放入背包,选择价值最大的方案。这就是通过状态转移方程dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1])
计算出的。 - 如果该物品的重量
weights[i-1]
超过当前容量j
,则无法将其放入背包,此时只能继承前i-1
件物品的最大价值,即dp[i][j] = dp[i-1][j]
。
4.4 返回最大价值
return dp[n][capacity];
循环结束后,dp[n][capacity]
就是前 n
件物品在背包容量为 capacity
时能够获得的最大价值,因此返回该值。
5. 复杂度分析
- 时间复杂度:
O(n * capacity)
,因为我们需要填充一个大小为n * capacity
的表。 - 空间复杂度:
O(n * capacity)
,因为我们使用了二维数组dp[][]
存储中间结果。
6. 空间优化
在上述实现中,我们用了二维数组 dp[][]
来存储所有状态。但实际上,在每一行 i
的状态转移时,只依赖于上一行 i-1
的值。因此,我们可以将二维数组压缩为一维数组,从而降低空间复杂度到 O(capacity)
。
public static int knapsackOptimized(int[] weights, int[] values, int n, int capacity) {int[] dp = new int[capacity + 1];for (int i = 1; i <= n; i++) {// 从大到小遍历容量,保证每个物品只被计算一次for (int j = capacity; j >= weights[i - 1]; j--) {dp[j] = Math.max(dp[j], dp[j - weights[i - 1]] + values[i - 1]);}}return dp[capacity];
}
关键点:
- 在每次迭代中,从容量
capacity
开始递减遍历,确保每个物品只更新一次。这种写法防止了在同一轮次中更新状态值时物品被重复选择。
7. 总结
0-1背包问题通过动态规划求解,有明确的状态转移方程。使用二维DP表来记录每个物品在不同容量下的最大价值,最终得到最优解。通过压缩空间,可以进一步优化到一维DP表。
相关文章:
动态规划算法之背包问题详细解读(附带Java代码解读)
动态规划中的背包问题(Knapsack Problem)是经典问题之一,通常用来解决选择一组物品放入背包使得背包的价值最大化的问题。根据问题条件的不同,背包问题有很多种变体,如0-1背包问题、完全背包问题、多重背包问题等。这里…...

Vue3+TypeScript二次封装axios
安装如下 npm install axios 第一步:创建config配置文件,用于存放请求后端的ip地址,用于后期打包后便于修改ip地址。 注:typescript要求参数要有类型。(ES6 定义对象 属性 类型 修改的是属性的值) inte…...

华为 HCIP-Datacom H12-821 题库 (16)
有需要题库的可以加下方Q群 V群进行学习交流 1. OSPF 邻居关系建立出现故障,通过 display ospf error 命令来检查,输出结果如图所示,根据图中内容分析,邻居建立失败的原因可能是以下哪一项? A、Process ID 不一致 B、…...

【论文分享精炼版】 sNPU: Trusted Execution Environments on Integrated NPUs
今天在COMPASS分享了之前写的一个博客,做了进一步的提炼总结,大家可以看看原文~ 今天分享的论文《sNPU: Trusted Execution Environments on Integrated NPUs》来自2024年ISCA,共同一作为Erhu Feng以及Dahu Feng。并且, 这两位作…...
MyBatis 入门之动态 SQL
文章目录 一、什么是动态 SQL二、MyBatis 中的动态 SQL 标签三、动态 SQL 的使用示例四、总结 在 Java 开发中,MyBatis 是一个非常流行的持久层框架,它提供了强大的 SQL 映射功能和动态 SQL 支持。动态 SQL 可以根据不同的条件动态地生成 SQL 语句&#…...
软工大二学生待办事项:
该文章会常年更新!坚持! 2024.9.10 学习打包部署 记录睡眠 开始刷一个算法 巩固Git版本控制工具的使用 巩固利用Idea使用版本管理工具,SQl编写 抓紧时间了解公司营业执照 坚持到周末再打瓦!...
MongoDB延迟查询
在 MongoDB 中,查看副本集成员之间的副本延迟可以通过以下步骤进行: 使用 rs.status() 命令: 这个命令提供了副本集的详细状态信息,包括每个成员的延迟情况。在 MongoDB shell 中,你可以执行以下命令: rs.s…...
python如何获取html中的所有链接
在Python中,获取HTML页面中的所有链接通常可以通过使用第三方库如BeautifulSoup或lxml来完成。这里,我将提供一个使用BeautifulSoup库的示例,因为它简单易用且功能强大。 首先,你需要安装BeautifulSoup和requests库(如…...
79-java static修饰的类能不能被继承
Java中的类可以被final关键字修饰,表示这个类不能被继承。如果一个类被final修饰,那么这个类不能被继承,也就是说,final类不能被继承。 另一方面,static关键字可以用来修饰内部类,这样的内部类是静态内部类…...

MacOS wine中文乱码问题
安装wine 1、brew update 执行失败,提示安装如下 2、git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow 3、git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow 3、brew update 4、brew in…...

基于Springboot的鲜花销售网站的设计与实现
项目描述 这是一款基于Springboot的鲜花销售网站的系统 模块描述 鲜花销售系统 1、用户 登录 在线注册 浏览商品 鲜花搜索 订购商品 查询商品详情 水果分类查看 水果加购物车 下单结算 填写收货地址 2、管理员 登录 用户管理 商品管理 订单管理 账户管理 截图...

安卓玩机工具-----适合安卓机型的“搞机工具箱” 功能齐全 玩机推荐
搞机工具箱最新版是一款相当出色的电脑端手机工具箱软件,搞机工具箱正式版功能强劲,可以帮助用户不需要root就能够直接对手机进行调节,方便对手机进行更加全面的掌控,搞机工具箱便捷好用,只需要根据文字提示及自己的需…...
数据分析-17-时间序列分析的平稳性检验
1 什么是时间序列 时间序列是一组按时间顺序排列的数据点的集合,通常以固定的时间间隔进行观测。这些数据点可以是按小时、天、月甚至年进行采样的。时间序列在许多领域中都有广泛应用,例如金融、经济学、气象学和工程等。 时间序列的分析可以帮助我们理解和预测未来的趋势和…...
Unity3D Android多渠道极速打包方案详解
在移动应用开发过程中,特别是在使用Unity3D进行Android游戏或应用开发时,多渠道打包是一个常见且重要的需求。不同的渠道(如Google Play、华为应用市场、小米应用商店等)可能需要不同的配置和包名,手动进行这些操作既耗…...
数据库中的主键和外键分别是什么意思?
让我们来聊聊数据库设计中非常重要的两个概念——主键(Primary Key)和外键(Foreign Key)。这两个概念对于保证数据的一致性和完整性至关重要。 主键(Primary Key) 主键是一个表中的一个或一组字段&#x…...
HTML5中`<ul>`标签深入全面解析
在HTML5的广阔天地里,<ul>标签作为无序列表的代言人,扮演着举足轻重的角色。它不仅能够整洁地罗列信息,还通过丰富的属性和样式选项,为网页设计师提供了无限的创意空间。本文将深入剖析<ul>标签的内核,详细…...

MongoDB日志级别
日志 查看当前的日志级别 根据你提供的 MongoDB 命令结果,命令 db.adminCommand({ getParameter: "logComponentVerbosity" }) 返回了 "ok" : 0,这意味着命令执行失败,没有成功获取到日志级别的配置信息。错误信息 &quo…...
Softmax回归--分类--有监督
输出和类别的维度一样。 一、当我们想将先线性层的输出直接视为概率,存在一些问题: 1.不能限制输出数字总和为1。 2.不能保证都是正数。 所以会使用softmax进行归一化。 二、交叉熵损失 交叉熵是一个衡量两个概率分布之间差异的很好的度量࿰…...

Jenkins生成html报告
下载插件 1.需要下载插件 html Publisher plugins 2.下载Groovy(设置css样式),默认没有css样式 在Job配置页面,增加构建步骤Execute system Groovy script,在Groovy Command中输入上面命令,即可: System.…...
牛客——查找字符串
B-你好,这里是牛客竞赛_牛客周赛 Round 59 (nowcoder.com) 返回值是子串或字符在 string 对象字符串中的位置 #include <bits/stdc.h> using namespace std; int T; string s; int main() { cin >> T; while(T --) { cin >>…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...