深入浅出:0 - 1 背包问题的滚动数组解法


在这里插入图片描述



一、引言

背包问题是数据结构中的经典问题,也是且具有挑战性的问题之一。而 0 - 1 背包问题更是基础中的基础,它在众多实际场景里都有广泛的应用,例如资源分配、货物装载等。在解决 0 - 1 背包问题时,动态规划是一种常用且高效的方法。本文将详细探讨 0 - 1 背包问题,并深入介绍如何使用滚动数组对其进行优化。

二、0 - 1 背包问题概述

2.1 问题定义

给定一组物品,每个物品都有对应的重量和价值,同时有一个具有最大容量限制的背包。在每个物品只能选择放入或不放入背包的规则下,我们需要找出一种物品组合,使得背包内物品的总价值达到最大。

2.2 具体示例

为了更直观地理解问题,我们来看一个具体的例子。有以下物品信息和背包容量:

物品编号重量价值
物品 0115
物品 1320
物品 2430
背包最大容量 bag_weight = 4

我们的目标就是从这些物品中选择合适的组合放入背包,让背包内物品的总价值最大。

三、动态规划与滚动数组思路

3.1 二维动态规划思路

动态规划解决 0 - 1 背包问题时,通常会使用二维数组 dp[i][j] 来记录状态。其中,i 表示考虑前 i 个物品,j 表示当前背包的容量,dp[i][j] 则表示在前 i 个物品中任意选择,放入容量为 j 的背包所能获得的最大价值。其状态转移方程为:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])

3.2 滚动数组优化思路

仔细观察状态转移方程可以发现,计算 dp[i][j] 时仅仅依赖于 dp[i - 1] 这一行的数据。这就意味着,我们不需要保存整个二维数组,只需要一个一维数组就可以完成计算。这种将二维数组压缩成一维数组的思想就是滚动数组。通过滚动数组,我们可以在不影响时间复杂度的情况下,显著降低空间复杂度。

四、具体分析全过程

4.1 初始化 dp 数组

我们使用一维数组 dp 来记录不同背包容量下能获得的最大价值。由于初始时还没有放入任何物品,所以所有容量下的最大价值都为 0。因此,dp = [0, 0, 0, 0, 0],其中 dp[j] 表示背包容量为 j 时的最大价值。

4.2 考虑物品 0(重量为 1,价值为 15)

外层循环开始遍历物品,当 i = 0 时,开始更新 dp 数组。内层循环从背包最大容量 bag_weight = 4 开始,到物品 0 的重量 weight[0] = 1 结束,且是从大到小遍历。

4.2.1 当 j = 4
  • 不选择物品 0:此时 dp[4] 保持初始值 0。
  • 选择物品 0j - weight[0] = 4 - 1 = 3dp[3] 初始为 0,所以 dp[3] + value[0] = 0 + 15 = 15
  • 取两者中的最大值更新 dp[4],即 dp[4] = max(0, 15) = 15
4.2.2 当 j = 3
  • 不选择物品 0dp[3] 为 0。
  • 选择物品 0j - weight[0] = 3 - 1 = 2dp[2] 为 0,所以 dp[2] + value[0] = 0 + 15 = 15
  • 更新 dp[3] = max(0, 15) = 15
4.2.3 当 j = 2

同理可得,dp[2] = max(0, dp[1] + value[0]) = max(0, 0 + 15) = 15

4.2.4 当 j = 1

dp[1] = max(0, dp[0] + value[0]) = max(0, 0 + 15) = 15

此时,考虑完物品 0 后,dp = [0, 15, 15, 15, 15],这表示当只有物品 0 可供选择时,在不同背包容量下能获得的最大价值。

4.3 考虑物品 1(重量为 3,价值为 20)

i = 1 时,继续更新 dp 数组。

4.3.1 当 j = 4
  • 不选择物品 1:此时 dp[4] 是上一轮考虑物品 0 后的结果,即 15。
  • 选择物品 1j - weight[1] = 4 - 3 = 1dp[1] 为 15,所以 dp[1] + value[1] = 15 + 20 = 35
  • 更新 dp[4] = max(15, 35) = 35
4.3.2 当 j = 3
  • 不选择物品 1dp[3] 为 15。
  • 选择物品 1j - weight[1] = 3 - 3 = 0dp[0] 为 0,所以 dp[0] + value[1] = 0 + 20 = 20
  • 更新 dp[3] = max(15, 20) = 20

因为 j 小于物品 1 的重量 3 时,无法放入物品 1,所以 j = 2j = 1 时,dp 值保持不变。

此时,考虑完物品 1 后,dp = [0, 15, 15, 20, 35]

4.4 考虑物品 2(重量为 4,价值为 30)

i = 2 时,更新 dp 数组。

4.4.1 当 j = 4
  • 不选择物品 2dp[4] 是上一轮考虑物品 1 后的结果,即 35。
  • 选择物品 2j - weight[2] = 4 - 4 = 0dp[0] 为 0,所以 dp[0] + value[2] = 0 + 30 = 30
  • 更新 dp[4] = max(35, 30) = 35

因为 j 小于物品 2 的重量 4 时,无法放入物品 2,所以 j 从 3 到 1 时,dp 值保持不变。

最终,考虑完所有物品后,dp = [0, 15, 15, 20, 35]

五、代码实现

weight = [1, 3, 4]
value = [15, 20, 30]
bag_weight = 4dp = [0] * (bag_weight + 1)for i in range(len(weight)):for j in range(bag_weight, weight[i] - 1, -1):dp[j] = max(dp[j], dp[j - weight[i]] + value[i])print(dp[bag_weight])

六、代码解释

6.1 初始化部分

定义了物品的重量、价值和背包的最大容量,并初始化一维 dp 数组,将所有元素初始化为 0。

6.2 双重循环部分

  • 外层循环for i in range(len(weight)) 遍历每个物品,i 表示当前正在考虑的物品编号。
  • 内层循环for j in range(bag_weight, weight[i] - 1, -1) 从背包最大容量开始递减到当前物品的重量。这样做是为了确保每个物品只被选择一次。
  • 状态转移方程dp[j] = max(dp[j], dp[j - weight[i]] + value[i]) 用于更新 dp 数组,在不选择当前物品和选择当前物品两种情况中取最大值。

6.3 输出部分

最终输出 dp[bag_weight],即背包在最大容量下能装下物品的最大价值。

七、复杂度分析

7.1 时间复杂度

O ( n × m ) O(n \times m) O(n×m),其中 n n n 是物品的数量, m m m 是背包的容量。因为需要遍历每个物品和每个背包容量。

7.2 空间复杂度

O ( m ) O(m) O(m),使用一维数组 dp 来记录状态,相比二维数组,空间复杂度得到了优化。

八、总结

通过本文的详细分析,我们深入了解了 0 - 1 背包问题的滚动数组解法。滚动数组的思想通过巧妙地利用状态转移方程的特性,将二维数组压缩成一维数组,在不影响时间复杂度的前提下,显著降低了空间复杂度。希望读者通过本文的学习,能够掌握 0 - 1 背包问题的解决方法,并将其应用到实际问题中。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring学习(spring容器、加载配置文件方式、获取bean的方式)

目录 一、加载spring配置文件的几种方式。 (0)工程文件初始化。 (1)加载类路径下的配置文件。(常见) (2)加载文件绝对路径的配置文件。 (3)加载多个配置文件。…

DeepSeek-R1论文阅读及蒸馏模型部署

DeepSeek-R1论文阅读及蒸馏模型部署 文章目录 DeepSeek-R1论文阅读及蒸馏模型部署摘要Abstract一、DeepSeek-R1论文1. 论文摘要2. 引言3. DeepSeek-R1-Zero的方法3.1 强化学习算法3.2 奖励建模3.3 训练模版3.4 DeepSeek-R1-Zero的性能、自进化过程和顿悟时刻 4. DeepSeek-R1&am…

华为动态路由-OSPF-骨干区

华为动态路由-OSPF-骨干区 一、OSPF简介 1、OSPF概述 OSPF是一种开放式的、基于链路状态的内部网关协议(IGP),用于在自治系统内部进行路由选择和通信。 OSPF是互联网工程任务组(IETF)定义的标准之一,被广…

RocketMQ - 常见问题

RocketMQ常见问题 文章目录 RocketMQ常见问题一:消息幂等问题1:什么是消费幂等2:消息重复的场景分析2.1:发送时消息重复2.2:消费时消息重复2.3:Rebalance时消息重复 3:通用解决方案3.1&#xff…

MySQL登录问题总结

不管何种数据库,使用的第一步都是先登录。 MySQL命令行登录语句:mysql -u username -P port -p -D database_name 登录MySQL的报错一般从报错信息都能得到反馈,常见报错原因分析如下,实例中的以test用户为例,登录环境为…

《千恋万花》无广版手游安卓苹果免费下载直装版

自取https://pan.xunlei.com/s/VOJS77k8NDrVawqcOerQln2lA1?pwdn6k8 《千恋万花》:柚子社的和风恋爱杰作 《千恋万花》(Senren * Banka)是由日本知名美少女游戏品牌柚子社(Yuzusoft)于2016年推出的一款和风恋爱题材…

【部署优化篇三】《DeepSeek边缘计算实战:把目标检测模型塞进树莓派,让AI在巴掌大的设备上“开天眼“》

“谁说只有超级计算机才能跑AI?今天咱们就要在树莓派上玩转DeepSeek目标检测,让这个巴掌大的小盒子变成会‘看’世界的智能终端!” 本文手把手教你从零开始,把最潮的目标检测模型塞进树莓派。全程高能预警,建议准备好你的树莓派4B/5和散热风扇,咱们这就开启边缘计算的魔法…

C++ Primer 类的作用域

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…

如何在 VS Code 中快速使用 Copilot 来辅助开发

在日常开发中,编写代码往往是最耗时的环节之一。而 GitHub Copilot,作为一款 AI 编码助手,可以帮助开发者 自动补全代码、生成代码片段,甚至直接编写完整的函数,大幅提升编码效率。那么,如何在 VS Code 中快…

剑指 Offer II 024. 反转链表

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20024.%20%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/README.md 剑指 Offer II 024. 反转链表 题目描述 给定单链表的头节点 head ,请反转链表&#xff…

通过API 调用本地部署 deepseek-r1 模型

如何本地部署 deepseek 请参考(windows 部署安装 大模型 DeepSeek-R1) 那么实际使用中需要开启API模式,这样可以无拘无束地通过API集成的方式,集成到各种第三方系统和应用当中。 上遍文章是基于Ollama框架运行了deepSeek R1模型…

【产品经理】需求分析方法论+实践

阐述了需求分析的基本认知,包括需求分析的定义、原则和内容。接着,文章详细介绍了需求分析的十个步骤,从收集需求到结果评审,为产品经理提供了清晰的操作指南。 作为产品经理,需求分析是一个最基本的工作,但…

【玩转 Postman 接口测试与开发2_020】(完结篇)DIY 实战:随书示例 API 项目本地部署保姆级搭建教程(含完整调试过程)

《API Testing and Development with Postman》最新第二版封面 文章目录 最新版《Postman 接口测试与开发实战》示例 API 项目本地部署保姆级搭建教程1 前言2 准备工作3 具体部署3.1 将项目 Fork 到自己名下3.2 创建虚拟环境并安装依赖3.3 初始运行与项目调试 4 示例项目的用法…

2025年02月19日Github流行趋势

项目名称:OmniParser 项目地址url:https://github.com/microsoft/OmniParser 项目语言:Jupyter Notebook 历史star数:12878 今日star数:2153 项目维护者:yadong-lu, ThomasDh-C, aliencaocao, nmstoker, kr…

侯捷 C++ 课程学习笔记:设计模式在面向对象开发中的应用

在侯捷老师的《C 面向对象开发》课程中,除了对面向对象编程的基础特性(封装、继承和多态)的深入讲解外,还引入了设计模式这一高级主题。设计模式是面向对象编程中的一种最佳实践,能够帮助开发者解决常见的设计问题&…

前七章综合练习

一,拓扑图 二,实验要求 不限 三,实验步骤 第一步,搭建拓扑图 如上 注意: 第二步,配置IP trust: client1 client2 fw untrusrt-1: fw r3 电信DNS 百度web-1 untrust-2&#xf…

个人shell脚本分享

在周一到周五做增量备份,在周六周日做完全备份 #!/bin/bash定义变量 SRC“/path/to/source” # 源目录 BKUP“/backup” # 备份主目录 FUL“KaTeX parse error: Expected EOF, got # at position 22: …ull" #̲ 完全备份目录 INC"BKUP/inc” # 增量备份…

C语言之函数封装技巧

目录 前言 一、函数在源代码中的三种状态 二、函数封装的运用 案例1&#xff1a;实现打印20以内的素数 案例2&#xff1a;存放因子数并返回长度 三、return返回与形参返回 四、<>与“” 五、解耦 总结 前言 在C语言中&#xff0c;函数封装是一种重要的技巧&#…

深度神经网络终极指南:从数学本质到工业级实现(附Keras版本代码)

深度神经网络终极指南&#xff1a;从数学本质到工业级实现&#xff08;附Keras版本代码&#xff09; 为什么深度学习需要重新理解&#xff1f;&#xff08;与浅层模型的本质差异&#xff09; 模型类型参数容量特征学习方式适合问题类型浅层模型102-104手动特征工程低维结构化数…

vue3 + thinkphp 接入 七牛云 DeepSeek-R1/V3 流式调用和非流式调用

示例 如何获取七牛云 Token API 密钥 https://eastern-squash-d44.notion.site/Token-API-1932c3f43aee80fa8bfafeb25f1163d8 后端 // 七牛云 DeepSeek API 地址private $deepseekUrl https://api.qnaigc.com/v1/chat/completions;private $deepseekKey 秘钥;// 流式调用pub…