背包算法(一)-01背包-史上最详细解答


  • 1. 题目
  • 2. 分析
    • 2.1 状态表示
    • 2.2 状态计算
  • 3. 实现
  • 4. 优化
  • 5. 测试

1. 题目

  • 问题描述:有n件物品和容量为m的背包,给出i件物品的重量以及价值value,还有数量number,求解让装入背包的物品重量不超过背包容量W,且价值V最大 。
  • 特点:这是最简单的背包问题,特点是每个物品只有一件供你选择放还是不放。

2. 分析

2.1 状态表示

一般用dp数组来计算动态规划问题,从以下两个方面对动态规划问题进行表示

  • 集合

    • v集合:物品价值
    • w集合:物品重量
    • 从前i个物品里面选取总重量<=j的所有物品的选法
  • 属性

    • max
    • min
    • count

本题属性是属于求最大价值,为max

2.2 状态计算

对于0和1背包的问题,我们计算的只是两个状态,即对于第i个物品选择放进去或者不放进去的问题。

  • 选择放进去
    表示在上一个物品的状态的时候,我的当前背包重量j需要减去当前这个物品的重量w[i],并且整个背包的价值需要加上当前这个物品的价值v[i],则状态方程为:
dp[i][j] = dp[i-1][j-w[i]] + v[i]
  • 选择不放进去
    实际上如果选择不放进去的时候,表示需要减去的w[i]和需要加上的v[i]都为0选择不放进去的状态方程则为:
# dp[i][j] = dp[i-1][j-0] + 0
dp[i][j] = dp[i-1][j]

由此我们可以得到状态转移方程:

dp[i][j] = max(dp[i-1][j-w[i]] + v[i], dp[i-1][j])

3. 实现

根据上面的状态转移方程我们可以得到01背包的二维解法:

def bag_two_2_0and1(items, weight):# 数据是从1开始的data_len = len(items)row = data_len + 1col = weight + 1# 生成二维数组# 原生的Python可以这么写:# dp = [[0] * col for _ in range(row)]# 使用numpy生成一个dp数组dp = np.array([0] * (row * col)).reshape(row, col)for i in range(1, row):if i == data_len:breakitem = items[i]v = item.get("value")w = item.get("weight")for j in range(1, col):if j >= w:no_input = dp[i-1][j]yes_input = dp[i-1][j-w] + vdp[i][j] = max(yes_input, no_input)else:dp[i][j] = dp[i-1][j]return dp[data_len-1][weight]

4. 优化

可以看的出来i这个变量其实就是表示“第i个”的一个递增序列,实际的这个背包的当前的状态只有重量(w)和价值(v)
根据刚才的状态方程:

# 不放进去
dp[i][j]=dp[i-1][j]# 放进去
dp[i][j]=dp[i-1][j-w[i]] + v[i]

观察两个状态方程,可以看到对于背包重量的状态ji无关,因此可以把上述方程简化为:

# 不放进去时候,重量不变,价值不变
dp[j] = dp[j] # 放进去的时候,背包重量和价值的变化
dp[j] = dp[j-w[i]] + v[i]

因此可以得到状态转移方程为:

dp[j] = max(dp[j-w[i]] + v[i], dp[j])

根据上述的状态转移方程来实现代码:

def bag_one_dim_0and1(items, weight):# 数据是从1开始的data_len = len(items)row = data_len + 1col = weight + 1# 生成一维数组# 原生的Python可以这么写:# dp = [[0] * col]# 使用numpy生成一个dp数组dp = np.array([0] * col)for i in range(1, row):if i == data_len:breakitem = items[i]v = item.get("value")w = item.get("weight")for j in range(weight, w, -1):dp[j] = max(dp[j-w]+v, dp[j])return dp[weight]

【1】此处为何倒序遍历呢?
首先我们观察优化后和优化前的状态转移方程:

# 优化之前
dp[i][j] = max(dp[i-1][j-w[i]] + v[i], dp[i-1][j])# 优化之后
dp[j] = max(dp[j-w[i]] + v[i], dp[j])

因此实际上优化后的状态转移方程是:

dp[j](第i轮的新值) = max(dp[j-w[i]] + v[i](第i-1轮的旧值), dp[j](第i-1轮的旧值))

优化后的状态转移方程实际上就是用最新的值把上一轮的值覆盖掉,所以可以在一个一维数组中完成状态转移,而且得保证:这一轮状态只能是由上一轮的状态推出来的。
为什么需要逆序遍历,此处如果从背包问题的物理操作去解释不好解释,简单的从数学上去理解就是:

我们这个j-w[i]是做减法的,而这个j又是数组的下标,做减法之后就表示是之前的数据。由于需要用新的值把旧的值进行覆盖,就需要保证在此数据是没有被改动过的,也就是原封不动第i-1轮的数据与当前第i轮的数据进行比较。因此此处如果是顺序的话,这个数据就已经是第i轮更新的数据与第i轮的数据进行比较了。

5. 测试

我们给出01背包的测试数据

{'items': [{'number': 1,'weight': 49,'value': 241}, {'number': 1,'weight': 25,'value': 724}, {'number': 1,'weight': 91,'value': 780}, {'number': 1,'weight': 76,'value': 824}, {'number': 1,'weight': 92,'value': 968}, {'number': 1,'weight': 53,'value': 276}, {'number': 1,'weight': 6,'value': 492}, {'number': 1,'weight': 53,'value': 745}, {'number': 1,'weight': 62,'value': 136}, {'number': 1,'weight': 94,'value': 568}],'total_weight': 200,'things_num': 10
}

输出:

3008

下一章:背包问题(二)-完全背包-史上最详细解答

背包算法(一)-01背包-史上最详细解答相关推荐

  1. Spark MLlib机器学习 | 算法综合实战(一)(史上最详细)

    ==========                         ========= 8.1.1 什么是机器学习 机器学习可以看做是一门人工智能的科学,该领域的主要研究对象是人工智能.机器学习利用 ...

  2. 背包算法轻松搞定——01背包算法、部分背包算法

    这篇文章过程讲得很详细,一文搞懂(点击看原文) 不懂之前觉得很难理解,觉得很复杂,其实没有必要.因为只要懂动态规划就可以很轻松搞定0-1背包算法(部分背包算法更简单,排序即可).之前看了很多篇文章都觉 ...

  3. 0-1背包算法和完全背包算法MATLAB代码实现

    有10件物品,它们的重量分别是5,8,3,2,6,6,5,4,7,5,,它们的价值分别是2,4,7,7,3,6,3,5,4,6,现在给你个承重为30的背包,试用0-1背包.完全背包算法,分别计算如何让 ...

  4. 史上最详细“截图”搭建Hexo博客——For Windows

    http://angelen.me/2015/01/23/2015-01-23-%E5%8F%B2%E4%B8%8A%E6%9C%80%E8%AF%A6%E7%BB%86%E2%80%9C%E6%88 ...

  5. IPV4与IPV6的区别(史上最详细)

    IPV4与IPV6的区别(史上最详细) 描述 IPv4 IPv6 地址 长度为 32 位(4 个字节).地址由网络和主机部分组成,这取决于地址类.根据地址的前几位,可定义各种地址类:A.B.C.D 或 ...

  6. 史上最详细MySQL5.5复制配置步骤,与以前版本的有所不同

    史上最详细MySQL5.5复制配置步骤,与以前版本的有所不同 http://codingstandards.iteye.com/blog/1535994 操作系统:CentOS 5.8 MySQL版本 ...

  7. 史上最详细唇语识别数据集综述

    更新:VIPL官网网页格式更改,导致旧的LRW1000链接无法访问,现已更新LRW1000数据集链接,内部包含申请需要的文件 推荐一个大佬的综述,关于实现唇语识别的多种途径. 说明:本文包括经常用语唇 ...

  8. GitChat·大数据 | 史上最详细的Hadoop环境搭建

    GitChat 作者:鸣宇淳 原文: 史上最详细的Hadoop环境搭建 关注公众号:GitChat 技术杂谈,一本正经的讲技术 [不要错过文末彩蛋] 前言 Hadoop在大数据技术体系中的地位至关重要 ...

  9. 史上最详细全中文 Cisco 3560交换机使用手册

    史上最详细全中文 Cisco 3560交换机使用手册 (末尾送交换机安全技术) 目 录 CISCO Catalyst 3560-E系列交换机的功能应用及安全解决方案 3 一.Cisco? Cataly ...

最新文章

  1. Cloudstack系统配置(三)
  2. 如何部署同一个Spring boot web 应用到不同的环境
  3. java fast math,Java FastMath.signum方法代码示例
  4. vue 父组件获取接口值传到子组件_vue父组件异步获取数据传给子组件的方法
  5. (转)ATOM介绍和使用
  6. 如何能写出,一份让 HR 认同的简历
  7. scala Basic 第三课
  8. C#实现--单链表(链式)
  9. javascript变量说明
  10. DN值、地表反射率、 表观反射率、发射率、辐射亮度、亮温名词解释
  11. java图片的缩放_Java的图片自动缩放
  12. 服务器中硬盘JBOD模式和RAID0模式区别
  13. opencv 绿色通道提取
  14. 先将输入的一系列整数中的最小值与第一个数交换,然后将最大值与最后一个数交换,最后输出交换后的序列。
  15. Wait for me和waitting for me有什么区别?
  16. Go Context 原理详解
  17. Android 画闹钟
  18. 流程引擎之Flowable简介
  19. flutter 微信语言选择_#Flutter项目(3)之仿写微信通讯录界面
  20. 【附源码】计算机毕业设计java游泳馆管理系统设计与实现

热门文章

  1. 阮一峰:为什么要写博客(转)
  2. JMeter 下载安装及环境变量配置
  3. java实现生成PDF文件
  4. 鸟哥的私房菜 --2如何学习linux
  5. 新版谷歌浏览器怎么查找和改变编码格式(新版chrome中工具,设置编码功能取消,新版如何添加插件)
  6. VC++阻止电脑熄屏与睡眠
  7. 畅捷通T+与旺店通·企业奇门对接集成报表单据查询打通创建其他入库单
  8. Linux安全之安装Snort(轻量级入侵检测系统)与使用
  9. 将图片转换为ico格式
  10. 学习PySide2基于Python开发人工智能系统应用