秒懂算法 | 子集树模型——0-1背包问题的回溯算法及动态规划改进

本文涉及的产品
模型训练 PAI-DLC,5000CU*H 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
交互式建模 PAI-DSW,每月250计算时 3个月
简介: 给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为W。一种物品要么全部装入背包,要么全部不装入背包,不允许部分装入。装入背包的物品的总重量不超过背包的容量。问应如何选择装入背包的物品,使得装入背包中的物品总价值最大?

image.png

01、问题分析——解空间及搜索条件

根据问题描述可知,0-1背包问题要求找出n种物品集合{1,2,…,n}中的一部分物品,将这部分物品装入背包。装进去的物品总重量不超过背包的容量且价值之和最大,即找到n种物品集合{1,2,…,n}的一个子集,这个子集中的物品总重量不超过背包的容量,且总价值是集合{1,2,…,n}的所有不超过背包容量的子集中物品总价值最大的。

按照回溯法的算法框架,首先需要定义问题的解空间,然后确定解空间的组织结构,最后进行搜索。搜索前要解决两个关键问题,一是确定问题是否需要约束条件(用于判断是否有可能产生可行解),如果需要,那么应如何设置?二是确定问题是否需要限界条件(用于判断是否有可能产生最优解),如果需要,那么应如何设置?

1●定义问题的解空间

0-1背包问题是要将物品装入背包,并且物品有且只有两种状态。第i(i=1,2,…,n)种物品是装入背包能够达到目标要求,还是不装入背包能够达到目标要求呢?很显然,目前还不确定。因此,可以用变量xi表示第i种物品是否被装入背包的行为,如果用“0”表示不被装入背包,用“1”表示装入背包,则xi的取值为0或1。该问题解的形式是一个n元组,且每个分量的取值为0或1。由此可得,问题的解空间为:(x1,x2,…,xn),其中xi=0或1,(i=1,2,…,n)。

2●确定解空间的组织结构

问题的解空间描述了2n种可能的解,也可以说是n个元素组成的集合的所有子集个数。可见,问题的解空间树为子集树。采用一棵满二叉树将解空间有效地组织起来,解空间树的深度为问题的规模n。图1所示描述了n=4时的解空间树。

image.png


图1 n=4时的解空间树

3●搜索解空间

(1) 是否需要约束条件?如果需要,那么应如何设置?

0-1背包问题的解空间包含2n个可能的解,是不是每一个可能的解描述的装入背包的物品的总重量都不超过背包的容量呢?显然不是,这个问题存在某种或某些物品无法装入背包的情况。因此,需要设置约束条件来判断所有可能的解描述的装入背包的物品总重量是否超出背包的容量,如果超出,就为不可行解;否则,为可行解。搜索过程将不再搜索那些导致不可行解的节点及其节点。约束条件的形式化描述为

image.png


(2) 是否需要限界条件?如果需要,那么应如何设置?

0-1背包问题的可行解可能不止一个,问题的目标是找一个所描述的装入背包的物品总价值最大的可行解,即最优解。因此,需要设置限界条件来加速找出该最优解的速度。

如何设置限界条件呢?根据解空间的组织结构可知,任何一个中间节点z(中间状态)均表示从根节点到该中间节点的分支所代表的行为已经确定,从z到其子孙节点的分支的行为是不确定的。也就是说,如果z在解空间树中所处的层次是t,从第1种物品到第t-1种物品的状态已经确定,接下来要确定第t种物品的状态。无论沿着z的哪一个分支进行扩展,第t种物品的状态就确定了。那么,从第t+1种物品到第n种物品的状态还不确定。这样,可以根据前t种物品的状态确定当前已装入背包的物品的总价值,用cp表示。第t+1种物品到第n种物品的总价值用rp表示,则cp+rp是所有从根出发的路径中经过中间节点z的可行解的价值上界。如果价值上界小于或等于当前搜索到的最优解描述的装入背包的物品总价值(用bestp表示,初始值为0),就说明从中间节点z继续向子孙节点搜索不可能得到一个比当前更优的可行解,没有继续搜索的必要;反之,则继续向z的子孙节点搜索。因此,限界条件可描述为

image.png

02、算法设计

从根节点开始,以深度优先的方式进行搜索。根节点首先成为活节点,也是当前的扩展节点。由于子集树中约定左分支上的值为“1”,因此沿着扩展节点的左分支扩展,则代表装入物品,此时,需要判断是否能够装入该物品,即判断约束条件成立与否,如果成立,就进入左孩子节点,左孩子节点成为活节点,并且是当前的扩展节点,继续向纵深节点扩展;如果不成立,就剪掉扩展节点的左分支,沿着其右分支扩展。右分支代表物品不装入背包,肯定有可能导致可行解。但是沿着右分支扩展有没有可能得到最优解呢?这一点需要由限界条件来判断。如果限界条件满足,说明有可能导致最优解,即进入右分支,右孩子节点成为活节点,并成为当前的扩展节点,继续向纵深节点扩展;如果不满足限界条件,则剪掉扩展节点的右分支,开始向最近的活节点回溯。搜索过程直到所有活节点变成死节点后结束。

算法伪码描述如下:

image.png

03、算法的改进

1●算法的改进思路

由C[i][j]的递归式(4-11)容易证明:在一般情况下,对每一个确定的i(1≤i≤n),函数C[i][j]是关于变量j的阶梯状单调不减函数(事实上,计算C[i][j]的递归式在变量j是连续变量,即为实数时仍成立)。跳跃点是这一类函数的描述特征。在一般情况下,函数C[i][j]由其全部跳跃点唯一确定,如图2所示。

image.png


图2 阶梯状单调不减函数C(i,j)及其跳跃点

利用该类函数由其跳跃点唯一确定的性质,来对0-1背包问题的算法knapsack进行改进,具体思路如下:

(1) 对每一个确定的i(1≤i≤n),用一个表p[i]来存储函数C[i][j]的全部跳跃点。对每一个确定的实数j,可以通过查找p[i]来确定函数C[i][j]的值。p[i]中的全部跳跃点(j,C[i][j])按j升序排列。由于函数C[i][j]是关于j的阶梯状单调不减函数,故p[i]中全部跳跃点的C[i][j]值也是递增排列的。

(2) p[i]可通过计算p[i-1]得到。初始时令p[0]={(0,0)}。由于函数C[i][j]是由函数C[i-1][j]与函数C[i-1][j-wi]+vi做max运算得到的。因此,函数C[i][j]的全部跳跃点包含于函数C[i-1][j]的跳跃点集p[i-1]与函数C[i-1][j-wi]+vi的跳跃点集q[i-1]的并集。容易得知,(s,t)∈q[i-1]当且仅当wi≤s≤W且(s-wi,t-vi)∈p[i-1]。因此,容易由p[i-1]来确定跳跃点集q[i-1],公式为

image.png


(3) 另外,设(a,b)和(c,d)是p[i-1]∪q[i-1]中的两个跳跃点,当c≥a且d<b时,(c,d)受控于(a,b),从而(c,d)不是p[i]中的跳跃点。也就是说,根据函数c[i][j]是关于j的阶梯状单调不减函数的特征,在跳跃点集p[i-1]∪q[i-1]中,按j由小到大排序,如果出现j增加,c[i][j]反而下降的点(j, c[i][j]),则不符合函数单调性,要舍弃。p[i-1]∪q[i-1]中的其他跳跃点均为p[i]中的跳跃点。

(4) 由此可得,在递归地由p[i-1]计算p[i]时,可先由p[i-1]计算出q[i-1],然后合并p[i-1]和q[i-1],并清除其中的受控跳跃点得到p[i]。

(5) 构造最优解。

第一步,初始时,i=n,j初始化为p[n]中的最大重量,m初始化为p[n]中的最优值。

第二步,检查p[i-1]中的所有点(w,v),如果w+wi=j并且v+vi=m,则xi=1,j=w,m=v,否则xi=0。重复第二步,直到i=0为止。

按照算法的改进思路,具体的求解过程如下:

初始时,令p[0]={(0,0)}。

image.png


在该并集中可以看到,跳跃点(2,3)受控于跳跃点(2,6),因此将(2,3)从并集中清除,得到

image.png


image.png


在该并集中可以看到,跳跃点(6,5)受控于跳跃点(4,9),因此将(6,5)从并集中清除,得到

image.png


image.png


由于跳跃点(13,15)和(15,18)已超出背包的容量W=10,因此将它们清除,得到

image.png


image.png


在该并集中可以看到,跳跃点(5,4)受控于跳跃点(4,9),因此将(5,4)从并集中清除,得到

image.png


image.png


同理,由于跳跃点(11,16),(12,17),(13,19)和(14,20)已超出背包的容量W=10,因此将它们清除,得到

image.png


image.png


在该并集中的受控跳跃点有(4,6)、(7,10)、(8,11)、(9,13)和(10,14),因此将它们从并集中清除,得到p[5]={(0,0),(2,6),(4,9),(6,12),(8,15)}。

p[5]中最后的跳跃点(8,15)给出了装入背包的最优值15及装入背包的物品重量8。

构造最优解过程:由于p[4]中的(4,9)⊕(4,6)=(8,15),故x5=1,j=4,m=9;由于p[3]中的所有点⊕(w4,v4)≠(j,m),故x4=0;p[2]中的所有点⊕(w3,v3)≠(j,m),故x3=0;p[1]中的(2,6)⊕(2,3)=(4,9),故x2=1,j=2,m=6;p[0]中的(0,0)⊕(2,6)=(2,6),故x1=1,j=0,m=0;求得的最优解为(1,1,0,0,1)。

04、Python实战

1●0-1背包问题的跳跃点算法

首先定义一个merge_points()函数,完成跳跃点集合的归并排序。接收两个有序的点集,将其归并为一个有序的点集。其代码如下:

image.png


其次,定义knapsack_improve()函数,完成各子问题跳跃点的计算,从而求出原问题的跳跃点,得到问题的最优值。

image.png


定义Traceback()函数,根据各子问题的跳跃点,逆向递推构造问题的最优解。其代码如下:

image.png


Python程序入口——main()函数,在main()函数中,给定5个物品的重量、价值和背包的容量,调用 knapsack_improve()函数得到最优值,再调用 Traceback()函数构造问题的最优解,最后将结果打印输出到显示器上。其代码如下:

image.png


输入结果为

最优解为:[1, 1, 0, 0, 1]

目录
相关文章
|
17天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
4天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
19 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
4天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
20 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
15天前
|
机器学习/深度学习 人工智能 算法
青否数字人声音克隆算法升级,16个超真实直播声音模型免费送!
青否数字人的声音克隆算法全面升级,能够完美克隆真人的音调、语速、情感和呼吸。提供16种超真实的直播声音模型,支持3大AI直播类型和6大核心AIGC技术,60秒快速开播,助力商家轻松赚钱。AI讲品、互动和售卖功能强大,支持多平台直播,确保每场直播话术不重复,智能互动和真实感十足。新手小白也能轻松上手,有效规避违规风险。
|
17天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
17天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
16天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
17天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
17天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法

热门文章

最新文章