01背包除了可以用形象的二维动态数组表示外,还可以使用空间复杂度更低的一维滚动数组。

目录

文章目录

前言

一、滚动数组的基本理解

二、确定dp及其下标含义

三、确定递推公式

四、确定初始化

五、确定遍历顺序

1.用物品(正序)遍历背包(正序)

实现代码:

手写图解:

2.用背包(正序)遍历物品(正序)

实现代码:

手写图解:

3.用物品(正序)遍历背包(逆序)

实现代码:

手写图解: ​编辑

总结



前言

晦涩难懂的滚动数组,有两个非常重要的点:①倒序②物品嵌套背包遍历


一、滚动数组的基本理解

我对于滚动数组的理解是:

滚动数组是基于二维数组之上产生的,之所以滚动数组能够用一维的方式去完成和二维同样的工作,原因就是在于这个滚动数组能够重复产生数据,进而有“滚动”的效果。

滚动数组的本质还是二维数组,只是数据不再产生新的行,只在一行上一直进行数据的覆盖更新,因此要特别注意数据污染的情况。

二、确定dp及其下标含义

由题意与我们将要创建的一维数组可知,dp[j]的含义是:背包容量为j时能装的最大价值。

三、确定递推公式

与二维dp数组相同,dp[j]的状态可以由两种状态得来:

①拿第i件物品(拿了以后,背包容量会减,价值会增加);

②不拿第i件物品;

所以可得:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);


四、确定初始化

由递推公式可得:dp[j]是由它之前的数据得来的,也即想要知道dp[j]的数值,就需要知道dp[j-x]的数据。(x是往前推的、未定的下标)

所以初始化只需要初始化dp[0]为0即可。(目前分析来说)

五、确定遍历顺序

与二维数组相同的是,一维dp数组仍然需要遍历物品和背包容量两种变量,只有这样才能模拟出将物品放入背包的过程。

1.用物品(正序)遍历背包(正序)

实现代码:

for (int j = 0; j < bagCapacity; j++){for (int i = 0; i < weight.size(); i++){// 背包容量够放if (j >= weight[i]){dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}// 不够放else{dp[j] = dp[j];}}}

手写图解:

由此我们可以很明显地看出在一维dp数组的情况下,数据覆盖的时候会发生污染,发现了物品0被放进dp[2]两次。

难道是遍历前后顺序不对?

2.用背包(正序)遍历物品(正序)

实现代码:

for (int i = 0; i < weight.size(); i++){for (int j = 0; j < bagCapacity; j++){// 背包容量够放if (j >= weight[i]){dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}// 不够放else{dp[j] = dp[j];}}

手写图解:

交换后,还是不可避免地发生了数据污染。

由此我们可以知道:

正序遍历的时候会将上一个物品装进背包两回,导致错误,而逆序就可保证dp[j]不受前面数据的影响(这时前面的数据仍然都是0),也就保证了每件物品只被放进去一次。

分析到这,我们也可以知道:初始化必须让整个dp数组的值都初始化为0(后面的dp[j]不能受前面数据的影响)。

3.用物品(正序)遍历背包(逆序)

实现代码:

for (int i = 0; i < weight.size(); i++){for (int j = bagCapacity; j >= 0; j--){// 背包容量够放if (j >= weight[i]){dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}// 不够放else{dp[j] = dp[j];}}}

手写图解: 

总结

最后我也验证了,既然遍历背包容量的时候需要倒序,那么可不可以再将倒序的背包和正序的物品颠倒位置?

运行结果:

原因是:从后向前遍历背包容量,见到能放进去的物品就跟已经已经在背包里的价值相比较,选择大的,但是这样一来不会发生价值的相加,只是看哪个物品价值高,并且在背包容量范围内,那就放进背包成为dp[j]。

遍历顺序在较复杂的dp题中是非常重要的一环。

【动态规划】01背包问题(滚动数组 + 手画图解)相关推荐

  1. 动态规划0-1背包问题滚动数组

    1.经典0-1背包问题 问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内选择物品使得物品的总价值最高. 回顾对于二维的0-1背包问题递推关系式: d p [ i ] [ j ] ...

  2. 动态规划 0-1背包问题 滚动数组

    定义 dp[j]是从物品0到i中挑选物品,放进容量为j的背包中的最大价值总和. 初始化 int dp[maxn]; memset(dp, sizeof(dp), -0x3f3f3f3f); 一维滚动数 ...

  3. 代码随想录42——动态规划:0-1背包理论基础、0-1背包滚动数组、416分割等和子集

    文章目录 1.0-1背包理论基础 1.1.概述 1.2.0-1背包 1.3.二维dp数组01背包--动规五部曲 1.4.完整测试代码 2.0-1背包滚动数组 2.1.一维滚动数组 2.2.一维dp数组 ...

  4. 01背包问题(当有的背包重量是非整数时)的递归(优化成动态规划+再用滚动数组优化)解法+一些动态规划(递归,搜索)的高级技巧

    当背包重量是整数时,动态规划可以用数组存储状态就可以了. 当背包重量是非整数时,用map存储状态就可以了!主要思路:  map(构造函数中参数comp是仿函数(或者叫函数对象))+递归优化(" ...

  5. 代码随想录算法训练营day41 | 动态规划 01背包问题基础 01背包问题之滚动数组

    day41 01背包问题基础 问题描述 举个栗子 二维dp数组01背包 1.确定dp数组以及下标的含义 2.确定递推公式 3.dp数组如何初始化 4.确定遍历顺序 5.举例推导dp数组 01背包问题之 ...

  6. 动态规划——0-1背包问题

    文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 1 0-1背包问题 背包能够承受的总重量一定w,每个物品的总量不同int[] weight表示.怎么放才 ...

  7. 动态规划——01背包问题 看此一篇文章就够了

    本文讲述经典算法--动态规划的 常见问题 01背包  一篇文章带你学会01背包问题,妈妈再也不担心我遇到01背包了!!! 问题描述 有n个物品,它们有各自的体积和价值,现有给定容量m的背包,如何让背包 ...

  8. 动态规划--01背包问题详解

    代码随想录day42和day43 动态规划 模块01背包问题 "即使到不了远方,心中也要有远方的模样." 文章目录 1. 01背包理论基础 1.1什么是背包问题 1.2二维dp数组 ...

  9. 动态规划—01背包问题

    原文作者:弗兰克的猫 原文地址:[动态规划]01背包问题 摘要: 01背包问题:n个物品放入容量为c的背包中. 常见解法: 分治法:递归计算,且存在重复计算的bug 自上而下填表法:从大到小使用递归计 ...

最新文章

  1. 面试官:什么是NIO?NIO的原理是什么机制?
  2. 当孩子面对困难的时候,家人可能的鼓励的方式
  3. Matlab 实现对 Excel sheet 重命名 合并单元格
  4. location.href、location.assign和location.replace的区别
  5. oracle表格颜色,如何在oracle中使用光标更新特定颜色
  6. 深入浅出TCPIP之实战篇—用c++开发一个http服务器(二十一)
  7. 循环结构格式 java
  8. 三丰三坐标编程基本步骤_加工中心开机回零的两种基本方式及常见问题的应对方法...
  9. [转载] python元组特点_python元组的优势有哪些
  10. 浏览器默认事件,事件监听,事件委托
  11. 整体资产评估需要资料清单
  12. 【律联云知产课堂】商标注册需要什么条件?
  13. 原则与思维模型--《思维模型》2
  14. 16 位 CPU 寄存器英文全称
  15. matlab勾股定理,勾股定理的两个物理证明
  16. 有多个按钮,点击一个变色,点击另一个变色,原来的恢复颜色的方法
  17. C语言 —— 你不得不知道的 scanf 的高级用法
  18. 公众号开发——自动回复功能
  19. 蓝桥杯真题:等差数列
  20. 使用xhshell 7 链接VMware虚拟机

热门文章

  1. 职场上流行的最恶毒的三句话
  2. 诛仙哪里炼器服务器最稳定,《诛仙网游》把你们见过最高炼器等级发出来
  3. 云顶之弈手游服务器维护,云顶之弈手游维护到几点?最新维护时间介绍[多图]...
  4. 项目迁移到OpenShift过程中遇到的问题总结
  5. jQuery 扩展插件
  6. 08-网线水晶头的连接方法
  7. 三大视频网站的会员争抢大战,电商化成为趋势?
  8. 512mb内存linux,小谈Windows Phone的“512MB 内存够用理论”
  9. 用知识脑图梳理碎片记忆
  10. 15 个优秀的响应式 CSS 框架