当前位置: 首页 > news >正文

动态规划算法之背包问题详细解读(附带Java代码解读)

动态规划中的背包问题(Knapsack Problem)是经典问题之一,通常用来解决选择一组物品放入背包使得背包的价值最大化的问题。根据问题条件的不同,背包问题有很多种变体,如0-1背包问题完全背包问题多重背包问题等。这里,我们详细介绍最经典的0-1背包问题,并提供代码的详细解读。

1. 0-1背包问题简介

在0-1背包问题中,有一个容量为 C 的背包和 n 件物品。每件物品有两个属性:重量 w[i]价值 v[i]。目标是选择若干件物品放入背包,使得总重量不超过 C,并且背包中物品的总价值最大化。

问题的约束:
  1. 每件物品要么选择(放入背包),要么不选择,因此称为 0-1 背包问题。
  2. 背包的总重量不能超过 C
  3. 要最大化背包中物品的总价值。

2. 动态规划的思路

动态规划适用于背包问题,因为它具有最优子结构重叠子问题的性质。解决这个问题的核心在于:针对每一个物品,都有两种选择——要么放进背包,要么不放进背包。

状态定义

定义 dp[i][j] 表示前 i 件物品放入容量为 j 的背包时所能获得的最大总价值。

状态转移方程

对于每件物品 i

  1. 如果不将第 i 件物品放入背包,则最大价值就是 dp[i-1][j],即前 i-1 件物品的最大价值。
  2. 如果将第 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代码解读)

动态规划中的背包问题&#xff08;Knapsack Problem&#xff09;是经典问题之一&#xff0c;通常用来解决选择一组物品放入背包使得背包的价值最大化的问题。根据问题条件的不同&#xff0c;背包问题有很多种变体&#xff0c;如0-1背包问题、完全背包问题、多重背包问题等。这里…...

Vue3+TypeScript二次封装axios

安装如下 npm install axios 第一步&#xff1a;创建config配置文件&#xff0c;用于存放请求后端的ip地址&#xff0c;用于后期打包后便于修改ip地址。 注&#xff1a;typescript要求参数要有类型。&#xff08;ES6 定义对象 属性 类型 修改的是属性的值&#xff09; inte…...

华为 HCIP-Datacom H12-821 题库 (16)

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

【论文分享精炼版】 sNPU: Trusted Execution Environments on Integrated NPUs

今天在COMPASS分享了之前写的一个博客&#xff0c;做了进一步的提炼总结&#xff0c;大家可以看看原文~ 今天分享的论文《sNPU: Trusted Execution Environments on Integrated NPUs》来自2024年ISCA&#xff0c;共同一作为Erhu Feng以及Dahu Feng。并且&#xff0c; 这两位作…...

MyBatis 入门之动态 SQL

文章目录 一、什么是动态 SQL二、MyBatis 中的动态 SQL 标签三、动态 SQL 的使用示例四、总结 在 Java 开发中&#xff0c;MyBatis 是一个非常流行的持久层框架&#xff0c;它提供了强大的 SQL 映射功能和动态 SQL 支持。动态 SQL 可以根据不同的条件动态地生成 SQL 语句&#…...

软工大二学生待办事项:

该文章会常年更新!坚持! 2024.9.10 学习打包部署 记录睡眠 开始刷一个算法 巩固Git版本控制工具的使用 巩固利用Idea使用版本管理工具,SQl编写 抓紧时间了解公司营业执照 坚持到周末再打瓦!...

MongoDB延迟查询

在 MongoDB 中&#xff0c;查看副本集成员之间的副本延迟可以通过以下步骤进行&#xff1a; 使用 rs.status() 命令&#xff1a; 这个命令提供了副本集的详细状态信息&#xff0c;包括每个成员的延迟情况。在 MongoDB shell 中&#xff0c;你可以执行以下命令&#xff1a; rs.s…...

python如何获取html中的所有链接

在Python中&#xff0c;获取HTML页面中的所有链接通常可以通过使用第三方库如BeautifulSoup或lxml来完成。这里&#xff0c;我将提供一个使用BeautifulSoup库的示例&#xff0c;因为它简单易用且功能强大。 首先&#xff0c;你需要安装BeautifulSoup和requests库&#xff08;如…...

79-java static修饰的类能不能被继承

Java中的类可以被final关键字修饰&#xff0c;表示这个类不能被继承。如果一个类被final修饰&#xff0c;那么这个类不能被继承&#xff0c;也就是说&#xff0c;final类不能被继承。 另一方面&#xff0c;static关键字可以用来修饰内部类&#xff0c;这样的内部类是静态内部类…...

MacOS wine中文乱码问题

安装wine 1、brew update 执行失败&#xff0c;提示安装如下 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、管理员 登录 用户管理 商品管理 订单管理 账户管理 截图...

安卓玩机工具-----适合安卓机型的“搞机工具箱” 功能齐全 玩机推荐

搞机工具箱最新版是一款相当出色的电脑端手机工具箱软件&#xff0c;搞机工具箱正式版功能强劲&#xff0c;可以帮助用户不需要root就能够直接对手机进行调节&#xff0c;方便对手机进行更加全面的掌控&#xff0c;搞机工具箱便捷好用&#xff0c;只需要根据文字提示及自己的需…...

数据分析-17-时间序列分析的平稳性检验

1 什么是时间序列 时间序列是一组按时间顺序排列的数据点的集合,通常以固定的时间间隔进行观测。这些数据点可以是按小时、天、月甚至年进行采样的。时间序列在许多领域中都有广泛应用,例如金融、经济学、气象学和工程等。 时间序列的分析可以帮助我们理解和预测未来的趋势和…...

Unity3D Android多渠道极速打包方案详解

在移动应用开发过程中&#xff0c;特别是在使用Unity3D进行Android游戏或应用开发时&#xff0c;多渠道打包是一个常见且重要的需求。不同的渠道&#xff08;如Google Play、华为应用市场、小米应用商店等&#xff09;可能需要不同的配置和包名&#xff0c;手动进行这些操作既耗…...

数据库中的主键和外键分别是什么意思?

让我们来聊聊数据库设计中非常重要的两个概念——主键&#xff08;Primary Key&#xff09;和外键&#xff08;Foreign Key&#xff09;。这两个概念对于保证数据的一致性和完整性至关重要。 主键&#xff08;Primary Key&#xff09; 主键是一个表中的一个或一组字段&#x…...

HTML5中`<ul>`标签深入全面解析

在HTML5的广阔天地里&#xff0c;<ul>标签作为无序列表的代言人&#xff0c;扮演着举足轻重的角色。它不仅能够整洁地罗列信息&#xff0c;还通过丰富的属性和样式选项&#xff0c;为网页设计师提供了无限的创意空间。本文将深入剖析<ul>标签的内核&#xff0c;详细…...

MongoDB日志级别

日志 查看当前的日志级别 根据你提供的 MongoDB 命令结果&#xff0c;命令 db.adminCommand({ getParameter: "logComponentVerbosity" }) 返回了 "ok" : 0&#xff0c;这意味着命令执行失败&#xff0c;没有成功获取到日志级别的配置信息。错误信息 &quo…...

Softmax回归--分类--有监督

输出和类别的维度一样。 一、当我们想将先线性层的输出直接视为概率&#xff0c;存在一些问题&#xff1a; 1.不能限制输出数字总和为1。 2.不能保证都是正数。 所以会使用softmax进行归一化。 二、交叉熵损失 交叉熵是一个衡量两个概率分布之间差异的很好的度量&#xff0…...

Jenkins生成html报告

下载插件 1.需要下载插件 html Publisher plugins 2.下载Groovy(设置css样式&#xff09;&#xff0c;默认没有css样式 在Job配置页面&#xff0c;增加构建步骤Execute system Groovy script&#xff0c;在Groovy Command中输入上面命令&#xff0c;即可&#xff1a; System.…...

牛客——查找字符串

B-你好&#xff0c;这里是牛客竞赛_牛客周赛 Round 59 (nowcoder.com) 返回值是子串或字符在 string 对象字符串中的位置 #include <bits/stdc.h> using namespace std; int T; string s; int main() { cin >> T; while(T --) { cin >>…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...