问题描述:

0-1背包问题:给定n种物品和一背包。物品 i 的重量似乎 wi,其价值为 vi,背包的容量为 c。问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大?

说实在的,书上讲的东西生涩难懂,我更偏向于看一些有趣的东西。 我们来换一个风格来描述这一个问题。
以下内容大部分来自 《算法图解》 一书。看完之后大有收获。

另一种风格的描述:

假设你是一个小偷,背着一个可装下4磅东西的背包,你可以偷窃的物品如下:

为了让偷窃的商品价值最高,你该选择哪些商品?

简单算法

最简单的算法是:尝试各种可能的商品组合,并找出价值最高的组合。

这样显然是可行的,但是速度非常慢。在只有3件商品的情况下,你需要计算8个不同的集合;当有4件商品的时候,你需要计算16个不同的集合。每增加一件商品,需要计算的集合数都将翻倍!这种算法的运行时间是O(2ⁿ),真的是慢如蜗牛

动态规划

解决这样问题的答案就是使用动态规划!下面来看看动态规划的工作原理。动态规划先解决子问题,再逐步解决大问题。

对于背包问题,你先解决小背包(子背包)问题,再逐步解决原来的问题。

比较有趣的一句话是:每个动态规划都从一个网格开始

背包问题的网格如下:

网格的各行为商品,各列为不同容量(1~4磅)的背包。所有这些列你都需要,因为它们将帮助你计算子背包的价值。

网格最初是空的。你将填充其中的每个单元格,网格填满后,就找到了问题的答案

1.吉他行

后面会列出计算这个网格中单元格值得公式,但现在我们先来一步一步做。首先来看第一行。


这是吉他行,意味着你将尝试将吉他装入背包。在每个单元格,都需要做一个简单的决定:偷不偷吉他?别忘了,你要找出一个价值最高的商品集合。

第一个单元格表示背包的的容量为1磅。吉他的重量也是1磅,这意味着它能装入背包!因此这个单元格包含吉他,价值为1500美元。

下面来填充网格。

与这个单元格一样,每个单元格都将包含当前可装入背包的所有商品。

来看下一个单元格。这个单元格表示背包容量为2磅,完全能够装下吉他!

这行的其他单元格也一样。别忘了,这是第一行,只有吉他可供你选择,换而言之,你假装现在还没发偷窃其他两件商品。

此时你很可能心存疑惑:原来的问题说的额是4磅的背包,我们为何要考虑容量为1磅、2磅等得背包呢?前面说过,动态规划从小问题着手,逐步解决大问题。这里解决的子问题将帮助你解决大问题。

别忘了,你要做的是让背包中商品的价值最大。这行表示的是当前的最大价值。它指出,如果你有一个容量4磅的背包,可在其中装入的商品的最大价值为1500美元。

你知道这不是最终解。随着算法往下执行,你将逐步修改最大价值。

2.音响行

我们来填充下一行——音响行。你现在处于第二行,可以偷窃的商品有吉他和音响。

我们先来看第一个单元格,它表示容量为1磅的背包。在此之前,可装入1磅背包的商品最大价值为1500美元。

该不该偷音响呢?

背包的容量为1磅,显然不能装下音响。由于容量为1磅的背包装不下音响,因此最大价值依然是1500美元。

接下来的两个单元格的情况与此相同。在这些单元格中,背包的容量分别为2磅和3磅,而以前的最大价值为1500美元。由于这些背包装不下音响,因此最大的价值保持不变。

背包容量为4磅呢?终于能够装下音响了!原来最大价值为1500美元,但如果在背包中装入音响而不是吉他,价值将为3000美元!因此还是偷音响吧。

你更新了最大价值。如果背包的容量为4磅,就能装入价值至少3000美元的商品。在这个网格中,你逐步地更新最大价值。

3.笔记本电脑行

下面以同样的方式处理笔记本电脑。笔记本电脑重3磅,没法将其装入1磅或者2磅的背包,因此前两个单元格的最大价值仍然是1500美元。

对于容量为3磅的背包,原来的最大价值为1500美元,但现在你可以选择偷窃价值2000美元的笔记本电脑而不是吉他,这样新的最大价值将为2000美元。

对于容量为4磅的背包,情况很有趣。这是非常重要的部分。当前的最大价值为3000美元,你可不偷音响,而偷笔记本电脑,但它只值2000美元。

价值没有原来高,但是等一等,笔记本电脑的重量只有3磅,背包还有1磅的重量没用!

在1磅的容量中,可装入的商品的最大价值是多少呢?你之前计算过。

根据之前计算的最大价值可知,在1磅的容量中可装入吉他,价值1500美元。因此,你需要做如下的比较:

你可能始终心存疑惑:为何计算小背包可装入的商品的最大价值呢?但愿你现在明白了其中的原因!余下了空间时,你可根据这些子问题的答案来确定余下的空间可装入哪些商品。笔记本电脑和吉他的总价值为3500美元,因此偷它们是更好的选择。

最终的网格类似于下面这样。

答案如下:将吉他和笔记本电脑装入背包时价值更高,为3500美元。

你可能认为,计算最后一个单元格的价值时,我使用了不同的公式。那是因为填充之前的单元格时,我故意避开了一些复杂的因素。其实,计算每个单元格的价值时,使用的公式都相同。这个公式如下。

你可以使用这个公式来计算每个单元格的价值,最终的网格将与前一个网格相同。现在你明白了为何要求解子问题了吧?你可以合并两个子问题的解来得到更大问题的解。

代码实现:

算法的核心是思想,当清楚了整个过程,那么写代码就简单了,直接来模拟上述的一个过程:

/*** @author:我没有三颗心脏* @create:2017-11-14-10:24*/
public class MaxBag {static int n;           // 描述物品个数static int c;           // 描述背包容量static int[] value;     // 描述物品价值static int[] weight;    // 描述物品重量public static void main(String[] args) {// 初始赋值操作value = new int[]{1500, 3000, 2000};weight = new int[]{1, 4, 3};c = 4;n = 3;// 构造最优解的网格:3行4列int[][] maxValue = new int[n][c];for (int i = 0; i < n; i++) {for (int j = 0; j < c; j++) {maxValue[i][j] = 0;}}   // end for// 填充网格for (int i = 0; i < n; i++) {for (int j = 1; j <= c; j++) {if (i == 0) {maxValue[i][j - 1] = (weight[i] <= j ? value[i] : 0);} else {int topValue = maxValue[i - 1][j - 1];  // 上一个网格的值int thisValue = (weight[i] <= j ?       // 当前商品的价值 + 剩余空间的价值(j - weight[i] > 0 ? value[i] + maxValue[i - 1][j - weight[i]] : value[i]): topValue);// 返回 topValue和thisValue中较大的一个maxValue[i][j - 1] = (topValue > thisValue ? topValue : thisValue);}   // end if}   // end inner for}   // end outer for// 打印结果二维数组maxValuefor (int i = 0; i < n; i++) {for (int j = 0; j < c; j++) {System.out.printf("%6d", maxValue[i][j]);}System.out.println();}}
}

最后打印出来的结果如下:

再增加一件商品将如何呢
假设你发现还有第四件商品可偷——一个iPhone!(或许你会毫不犹豫的拿走,但是请别忘了问题的本身是要拿走价值最大的商品)

此时需要重新执行前面所做的计算吗?不需要。别忘了,动态规划逐步计算最大价值。到目前为止,计算出的最大价值如下:

这意味着背包容量为4磅时,你最多可偷价值3500美元的商品。但这是以前的情况,下面再添加表示iPhone的行。

我们还是从第一个单元格开始。iPhone可装入容量为1磅的背包。之前的最大价值为1500美元,但iPhone价值2000美元,因此该偷iPhone而不是吉他。

在下一个单元格中,你可装入iPhone和吉他。

对于第三个单元格,也没有比装入iPhone和吉他更好的选择了。

对于最后一个单元格,情况比较有趣。当前的最大价值为3500美元,但你可以偷iPhone,这将余下3磅的容量。

3磅容量的最大价值为2000美元!再加上iPhone价值2000美元,总价值为4000美元。新的最大价值诞生了!

最终的网格如下。

问题:沿着一列往下走,最大价值可能降低吗?

答案是:不可能。因为每次迭代时,你都存储的是当前的最大价值。最大价值不可能比以前低!

转载声明

简书ID:@我没有三颗心脏
github:wmyskxz
https://www.jianshu.com/p/a66d5ce49df5

数据结构——背包问题相关推荐

  1. 数据结构背包问题c语言思路,【数据结构与算法】背包问题总结梳理

    背包问题总结分析 背包问题是个很经典的动态规划问题,本博客对背包问题及其常见变种的解法和思路进行总结分析 01背包 问题介绍 有 N 件物品和一个容量是 V 的背包.每件物品只能使用一次. 第 i 件 ...

  2. 数据结构背包问题c语言思路,C语言学习趣事_数据结构_经典命题_1_背包问题_分析_1...

    /*1.问题描述 假设有一个能装入总体积为T的背包和n件体积分别为w1,w2,-wn的物品, 能否从n件物品中挑选若干件恰好装满背包,即使w1+w2+-+wm=T, 要求找出所有满足上述条件的解. 例 ...

  3. 数据结构与算法总结——背包问题与组和问题

    数据结构与算法总结--背包问题与组和问题 数据结构与算法总结--背包问题与组和问题 1. 背包问题 2.背包问题的变形 3. 组和问题 总结 数据结构与算法总结--背包问题与组和问题 我觉得学习算法很 ...

  4. 完全背包问题贪心算法c语言,数据结构与算法学习之路:背包问题的贪心算法和动态规划算法...

    一.背包问题描述: 有N种物品和一个重量为M的背包,第i种物品的重量是w[i],价值是p[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包重量,且价值总和最大. 二.解决方法: 1.贪心算 ...

  5. python【数据结构与算法】01背包问题(附例题)

    文章目录 1 定义 2 例题 3 压缩 1 定义 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使价值总和最大. 基本思路 这是最基础的背包 ...

  6. 【算法数据结构Java实现】Java实现动态规划(背包问题)

    1.背景      追随着buptwusuopu大神的脚步,最近在研习动态规划.动态规划应该叫一种解决问题的思想,记得又一次去某公司面试就被问到了这个. 多于动态规划的理解,大致是这样的,从空集合开始 ...

  7. 【算法与数据结构】—— 动态规划之背包问题

    动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...

  8. 【数据结构/leetcode】背包问题部分代码

    416.分割等和子集 给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: 输 ...

  9. 【数据结构与算法知识】—动态规划之01背包问题

    阅读之前看这里

  10. 资料分享:送你一本《数据结构与算法JavaScript描述》电子书!

    数据结构 是掌握计算机编程必须具备的技能.通常情况下,我想掌握一门编程语言所用的方法就是利用这门语言把数据结构中线性表.栈.队列.字符串.动态数字.整数集合.树.图.搜索.排序等涉及的算法全部写一遍. ...

最新文章

  1. 源码安装zabbix3.2.7时PHP ldap Warning
  2. CSS+js弹出居中的背景半透明div层
  3. 2021-04-21--中标麒麟--yum源修改
  4. MyBatis 相同事物查询缓存问题
  5. UVa 590 Always on the run(简单链式DP)
  6. dyaddown matlab,matlab 采样函数
  7. Spring @Transactional实际如何工作?
  8. 再谈布局,栅栏式自适应布局的学习和实现(calc自适应布局)
  9. linux桥接设置静态,centos6.10 桥接模式下配置静态ip
  10. linux ftp 没反应,【已回应】FTP无法使用怎么办
  11. python函数的特性_Python学习(007)-函数的特性
  12. pandas小记:pandas基本设置
  13. 杰出的橙色网站设计案例
  14. 3dmax模型带材质导出obj格式文件的方法与步骤
  15. 图像检索代码python_图像检索系列——利用深度学习实现以图搜图
  16. [译] The Cost Of JavaScript
  17. Python采集全球疫情数据并做可视化分析
  18. 设置计算机每天定时自动开关机,如何设置电脑定时自动关机?
  19. codelite交叉编译动态库学习记录
  20. java idwork长度_java 字符串id

热门文章

  1. 生活哪些方面作用计算机,电脑在我们的生活中起着重要的作用
  2. 谷歌,互联网界的“彩蛋狂魔”
  3. activeMQ安装问题wrapper | Launching a JVM... wrapper | Unable to execute Java command.
  4. mp3格式怎么转html格式转换器,flac转mp3格式转换器 如何将flac格式的音频文件转换为MP3格式...
  5. 扩展卢卡斯 (板子)
  6. sudo: no valid sudoers sources found, quitting
  7. JAVA操作共享文件夹文件、下载、读取(windows、Linux通用)
  8. 《修炼——我的职场十年》 摘录
  9. 关于驱动程序与BSP的区别
  10. saas、paas、laas 的概念与区别