动态规划Dynamic Programing学习笔记 打劫问题 凑整问题 背包问题

  • 学习资源
    • Example1. 打家劫舍问题 looting problem
    • Example2. 凑整问题
  • Example3. 背包问题

学习资源

灯神的视频是我目前个人觉得讲解最清晰的动态规划教学,这篇文章是对他视频内容的汇总,在此基础上我还个人补充了背包问题的解决方案。
灯神的b站小课堂

Example1. 打家劫舍问题 looting problem

题目模型简化如下: 给定数组arr=[4,1,1,9,1],从中选择数字来使得总和最大,注意不能选择相邻的数字。例如,选择4后,不能选择1;选择9后,不能选择9左右两侧的数字1。

  1. 模型建立。我们拿出一组新的数组arr=[1,2,4,1,7,8,3],将其按顺序分别编号为0-6。如图

  2. 假定opt(6)表示:从前6个数字中选出总和最大的最佳方案(也就是我们期望得到的结果),同理opt(5)表示从前五个数字中选出来总和最大的方案……依次类推。

  3. 我们在这个基础上进行推理:对于第六个数字,我们有选择和不选择这两种操作,当我们选择第六个数时,根据规则就无法选择第五个数字,因此opt(6)=opt(4)+arr[6],即在这种情况下,opt6的值等于前四个数字中选出的最大值加上第六个数的数值。如果我们不选择第六个数,那么opt(6)=opt(5),即前五个数所能选出总和最大的值。

  4. 根据这个逻辑,为了算出opt6,我们需要经历以下过程。加号表示选择当前数,减号表示不选择当前数。整个过程的树状图如下根据上图所示的逻辑,我们可以从中推出普遍的递推规律。因为我们是求最大值,所以前i个数字所能构成的最大总和为opt(i)=max(opt(i-1),opt(i-2)+arr[i]),其中,opt(i)是我们放弃选择第i个数时所得到的前i-1个数能构成的最大值;opt(i-2)+arr[i] 是我们选择第i个数时能得到的最大值。

  5. 寻找出口条件#当i=0时 opt(1)=max(arr[1],arr[0]) #当i=1时 opt(0)=arr(0)

  6. 用代码来实现当前逻辑。分两种,首先是recursive method

import numpy as nparr=[1,2,4,1,7,8,3]def rec_method(arr,i):  #recursive methodif i==0:            #在if和elif中填写我们前面推出来的出口条件return arr[0]elif i==1:return max(arr[0],arr[1])else:             #在else中填写我们发现的基本逻辑a=rec_method(arr,i-1)b=rec_method(arr,i-2)+arr[i]return max(a,b)rec_method(arr,6)

运行这段代码后可以发现最终结果为15。这个地方我们运行的基本原理就是在函数中不停地调用自身,最终由opt6出发推演至opt0,直到算出答案(如上面我手绘的树状图)。这种办法虽然变成起来思路比较直观,但在该推演过程中有很多重复的运算。回到上面的树状图,该办法在计算opt6时,重复计算了opt4和opt3,我分别用黄色、绿色荧光笔将重复部分标记了起来。

当arr内数据和i的数量变大时,使用这种办法的运算成本将大幅升高。接下来介绍非recursive的计算方法

#续上面的代码
def nonrec_method(arr):opt = np.zeros(len(arr)) #建立数组来存储opt数据opt[0]=arr[0]opt[1]=max(arr[1],arr[0])for i in range(2,len(arr)):A = opt[i-2]+arr[i]B = opt[i-1]opt[i] = max(A,B)return opt[len(arr)-1]
nonrec_method(arr)

输出结果为15.0。该种方法可以理解为逆着树状图,由opt0出发一步一步推演至最终结果opt6,好处在于每一步的结果我们都储存在了数组中,节约了不少计算资源。

Example2. 凑整问题

题目要求如下,给定数组arr=[3,34,4,12,5,2],判断能否实用数组内的数构成S(s为一个数)。

  1. 模型建立:假定S=9,将arr中的数据从0-5进行编号。如图

  2. 我们设subset(i,S),其中i表示使用前i个数字,S为我们期望拼凑成的数。例如,subset(5,9)表示使用前五个数字来拼凑出9的总和。subset(2,3)表示使用前两个数字拼凑出3。我们从这个符号出发,开始推理过程,首先考虑subset(5,9),我们此时要用前五个数来拼出9,首先判断第五个数。在这个地方我们有两种选择,第一种选择是使用第五个数来拼凑出9,那么选择后的情况就变成了subset(4,7),表示用前4个数去凑成7。第二种选择是不使用第五个数,那么情况就变成了subset(4,9)。绘制成树状图如下

  3. 由此我们可以推出普遍的递推规律,若使用前i个数凑成S,递推规律表达式为其中arr表示存放数据的数组。

  4. 接下来,我们开始寻找出口条件,第一种情况是当S下降为0时,说明前面的数字已经完成了拼凑任务,此时应该返回True,表示能够拼凑出S;第二种情况是当i下降为0时,S仍然不为0。i=0说明已经引导到了数组的首位数,如果此时满足arr[0]==S,那么说明能够凑出S,返回True。如果不相等则说明arr中的数字无法拼成S,返回False。这两个出口条件总结如下:

if i==0: return arr[0]==S #如果arr[0]==S,说明能凑成,返回True;反之则返回False
elif S==0: return True
  1. 通过Recursive的方法编写的python源码如下:
import numpy as nparr=[3,34,4,12,5,2]def opt(arr,i,S):if S==0 :return Trueelif i==0:return S==arr[i]elif arr[i]>S:return opt(arr,i-1,S)else:A = opt(arr,i-1,S-arr[i])B = opt(arr,i-1,S)return A or B
print(opt(arr,len(arr)-1,1))

运行后结果为True,说明arr内的数字能够凑出9。

  1. 上面的recursive法虽然解决了这个问题,但由于本质是重复的迭代计算,随着数组复杂度的增加,运算占用资源会大大上升,速度也会明显变慢。在这样一情况下,我们使用另一种方法来解决这个问题。
def nonrec_opt(arr,S):subset = np.zeros([len(arr),S+1],dtype=bool)subset[0,:]=Falsesubset[:,0]=Trueif arr[0]<S:subset[0,arr[0]]=Truefor i in range(1,len(arr)):for j in range(1,S+1):if arr[i]>j:subset[i,j] = subset[i-1,j]else:A = subset[i-1,j-arr[i]]B = subset[i-1,j]subset[i,j] = A or Bl,w = subset.shapeprint(subset)return subset[l-1,w-1]print(nonrec_opt(arr,9))

运行后输出结果同样为True,但该方法中,我们使用numpy创建了一个数组,依次计算并存储了各个阶段中subset的bool值,避免了前面recursive method中出现的重复计算的问题。本质上,这种办法相当于创建了一个如下的bool表格:红圈就是我们最终想要得到的结果,即`subset(5,9)

Example3. 背包问题

  1. 题目要求,有以下编号为1-4的四件物品,他们各自的体积及其所占据的空间如下表格所示,现有一个容积为8的背包,如果我们想让该包中所存放的物品价值最大,应该怎么放?
  2. 题目分析:在Example2中,我们分析了凑整问题的解决方案,当前这个背包问题与凑整问题有相似之处但更为复杂:一点相似之处在于把物品放入背包,相当于是一个条件弱化的凑整问题,不需要恰好相等,只需要保证放入物品的总体积小于背包容积即可。不同之处在于,前一个凑整问题的返回值可为布尔量(即0和1),0表示当前方案不可行,1表示可以凑出该数值;本题中不再单纯的返回一个布尔量,而是返回背包内物品的总价值,我们取最终价值最高的方案来当作最优解。
  3. 和Example2一样的方法,我们首先设计表格:
  4. 表格中横轴从0开始直至背包体积、纵轴从0开始直至物体总数量。相应地,我们在纵轴的旁表上相应物品编号的属性。其中,我用S,size来表示物体体积、V,value表示物品价值。 首先,我们可以在第一行和第一列全部填上0,因为在背包容积为0和包内物品数量为0的这两种情况下,包内物体的总价值都是恒为0的。接下来,我们看编号为1的这一行,在到横轴的背包体积达到2之前,一号物品始终是放不进书包的,故opt(1,1)为0(这个地方opt表示:当物品数量为1,背包容量为1时,背包内物品的最大总价值 ,后面还会常用到)。当背包容积为2时,此时能够放进第一个物品,我们有两种选择,放入一号物品或者不放入。此时的opt(1,2)也就等于这两种选择中让包内物品价值更大的那个选择,即opt(1,2)=max( 放入,不放入 )。如果放入,背包体积变为2-2=0,物品数量1-1=0,即opt(0,0)再加上第一件物品的价值,opt(0,0)+3。如果不放,说明放弃一号物品,物品数量-1,背包容积不变,即opt(0,2)。如下图:
  5. 按照同样的逻辑,我们可以依次将该表格填下去,而每一次决策(选或不选)均取决于哪一种选择能带来更高的物品总价值,且总能参考前面已经得到的opt值。完成的表格如下,(有时间了再更新)

灯神动态规划(Dynamic Programing)学习笔记 打劫问题 凑整问题 背包问题 例题+原理+源码超详细讲解相关推荐

  1. OpenCV学习笔记(三):图像对比度、亮度调整源码

    OpenCV学习笔记(三):图像对比度.亮度调整源码 主函数: #include <opencv2/opencv.hpp>using namespace cv;using namespac ...

  2. Python学习笔记:7.5.1 Django快速建站 -源码版本管理

    前言:本文是学习网易微专业的<python全栈工程师 - Django快速建站>课程的笔记,欢迎学习交流.同时感谢老师们的精彩传授! 一.课程目标 了解源码版本管理的意义 掌握初步的git ...

  3. Vue学习笔记之13-webpack的配置 傻子看了都会配置的超详细教程

    本文中所使用的webpack配置相关版本如下, 如果你想要用新一点的版本, 可能需要根据报错的提示,安装额外的内容 webpack 3.6.0 css-loader 2.0.2 style-loade ...

  4. zabbix编译php_【Zabbix学习笔记】五、LNMP之PHP7.4.1源码编译安装

    PHP7.4.1已于12月18日发布,先来体验一下~ 了解PHP7.4.1的新特性请点击:php7.4新特性 安装环境 操作系统:Centos7 PHP版本: PHP 7.4.1 Web服务器:Ngi ...

  5. 华为鸿蒙系统学习笔记5-华为方舟编译器正式开源及相关源码下载

    8月9日至8月11日,华为面向全球开发者的2019年开发者大会,将在东莞松山湖举行.据悉,今年也是华为第一次在华为松山湖基地欧洲小镇里举办开发者大会. 前不久,余承东曾在微博上预告:"让我们 ...

  6. PostgreSQL学习笔记YY(2)--Ubuntu下使用DDD调试查看源码(原创)

    说明:前一段时间一直在FreeBSD的操作系统环境下进行实验,但是由于多次安装桌面系统失败,所以无法及时更新日志.昨天换了Ubuntu系统,在Unix 环境下摸索了3天之后,终于在Ubuntu上编译, ...

  7. 张飞硬件设计与开发 学习笔记(第一部 线性稳压电源设计) 含理解,超详细!

    第一部 线性稳压电源的设计 前言 一.线性稳压电源的设计 1.课程概述.交流到直流降压简介 2.整流原理介绍.电阻选型.二极管介绍 3.电容的理解与选型 4.稳压电路的设计流程 5.元件详细选型 6. ...

  8. react学习笔记 react-router-dom react-redux基础使用及手写基础源码 组件反射 react原理

    vdom diff 高效的diff算法 新老vdom树比较 更新只需要更新节点 数据变化检测 batch dom读写 组件多重继承 //parent components export default ...

  9. PyTorch深度学习基础之Reduction归约和自动微分操作讲解及实战(附源码 超详细必看)

    创作不易 觉得有帮助请点赞关注收藏~~~ 一.PyTorch的Reduction操作 Reduction运算的特点是它往往对一个Tensor内的元素做归约操作,比如torch.max找极大值,torc ...

  10. PJ可能会用到的动态规划选讲-学习笔记

    PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...

最新文章

  1. SAP MM 自定义条件类型出现在采购信息记录的'条件'界面里 ?
  2. Java NIO之选择器
  3. 音视频技术开发周刊 | 135
  4. 2.2基本算法之递归和自调用函数_一文学会递归解题
  5. java和vb.net des加密_vb.net DES加密与解密
  6. python标注工具_Python labelImg 图像标注工具安装及使用教程windows版(亲测有效)
  7. http error 502.5
  8. 通道注意力机制_即插即用,Triplet Attention机制让Channel和Spatial交互更加丰富(附开源代码)...
  9. 《Linux编程》学习笔记 ·003【Shell编程】
  10. 首批 8 款 5G 手机获 3C 认证;iPhone6 系列停产;Android Q Beta 5 发布 | 极客头条
  11. java输出矩形_java输出长方形求解答
  12. Linux内核网络编程
  13. 电力拖动自动控制系统复习补充
  14. 龙芯2f平台下 Debain 6编译Lighttpd并支持C语言cgi脚本编程
  15. RGB Triplets(后缀和)
  16. [java] JavaMail发送邮件
  17. 防火墙/入侵防护系统IPS
  18. 《JavaScript》JavaScript教程
  19. WAP(手机网站)基础知识
  20. photoshop 快速画直线

热门文章

  1. Node Express框架快速入门教程
  2. 【Laravel系列6.3】框架启动与服务容器源码
  3. 兜兜转转。最终还是选择了它——C语言学习历程
  4. 用什么软件测试内存条稳定,如何检测内存条的好坏有什么软件
  5. 35岁腾讯员工被裁员感叹:北京一套房,存款700多万,失业好焦虑
  6. uva-10177 - (2/3/4)-D Sqr/Rects/Cubes/Boxes?
  7. 什么叫特立独行,其实不过是活在自己的节奏里
  8. 腾讯android一键root工具,腾讯一键Root工具
  9. chmod 权限详细解析(rw)
  10. android:ems什么意思