回溯算法——0-1背包问题

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验目的是使学生消化理论知识,加深对讲授内容的理解,尤其是一些算法的实现及其应用,培养学生独立编程和调试程序的能力,使学生对算法的分析与设计有更深刻的认识。

上机实验一般应包括以下几个步骤:

(1)、准备好上机所需的程序。手编程序应书写整齐,并经人工检查无误后才能上机。

(2)、上机输入和调试自己所编的程序。一人一组,独立上机调试,上机时出现的问题,最好独立解决。

(3)、上机结束后,整理出实验报告。实验报告应包括:题目、程序清单、运行结果、对运行情况所作的分析。

实验八 回溯算法——0-1背包问题

一、实验目的与要求

1. 熟悉0-1背包问题的回溯算法。

2. 掌握回溯算法。

二、实验内容

用回溯算法求解下列“0-1背包”问题:

给定n 种物品和一个背包。物品i 的重量是w i ,其价值为v i ,背包的容量为C 。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

三、实验步骤

1. 理解算法思想和问题要求;

2. 编程实现题目要求;

3. 上机输入和调试自己所编的程序;

4. 验证分析实验结果;

5. 整理出实验报告。

实验提示:

(1)回溯算法求解0-1背包问题分析

回溯法通过系统地搜索一个问题的解空间来得到问题的解。为了实现回溯,首先需要针对所给问题,定义其解空间。这个解空间必须至少包含问题的一个解(可能是最优的)。 然后组织解空间。确定易于搜索的解空间结构。典型的组织方法是图或树。一旦定义了解空间的组织方法,即可按照深度优先策略从开始结点出发搜索解空间。并在搜索过程中利用约束函数在扩展结点处剪去不满足约束的子树,用目标函数剪去得不到最优解的子树,避免无效搜索。用回溯法解题的步骤:

1)针对所给问题定义问题的解空间;

2)确定易于搜索的解空间结构;

3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效的搜索。

0-1背包问题的数学描述为:n 个物品,物品i 的重量是w i 、其价值为v i ,其中0≤i ≤n-1,背包的容量为C 。用x i 表示物品i 被装入背包的情况,如果物品Pi 被选中,则x i =1;否则x i =0。求满足目标函数∑-=⨯=10max n i i i v x

F 和约束方程C w x n i i i ≤⨯∑-=1

0的物品组合(x 0,x 1,x 2,…,x n-1) 与相应的总价值V 。

1)针对所给问题定义问题的解空间。

根据上述0-1背包问题的数学描述,解向量可以表示成X={ x0,x1,x2,…,x n-1) | x i=1或x i=0} 。若n = 3 ,则此0-1背包问题的解空间为{(0,0,0),(0,0,1) ,(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)}。

2)确定易于搜索的解空间结构。

可以用树的形式将解空间表达出来。树中从第i层到第i+1层的边上的值表示解向量中x i的取值,并假定第i层的左子树描述物品Pi被装入背包的情况,右子树描述物品Pi被拒绝的情况。则该0-1背包问题的状态空间树就表示为一棵高度为n的完全二叉树(如图l所示) 。从根结点到叶子结点的任一路径就对应解空间中的一个解向量。

3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效的搜索。

构造出问题的状态空间树以后,就可以从其根结点出发搜索解空间,即决定每个物品的取舍。为了使目标函数的值增加最快,可以优先选择价值最大的物品装入背包,然后是价值量次之的物品,……,直至背包装不下为止。但是,如果所选择的物品重量很大,使得背包载重量消耗速度太快,以至后续能装入背包的物品迅速减少,使得继续装入背包的物品在满足了约束方程的要求以后,无法达到目标函数的要求。因此,最好优先选择那些既使目标函数的值增加最快。又能使背包载重量消耗速度较慢的物品装入背包。为了达到这个目的,首先把所有物品按价值重量比的非增顺序排列,然后按照这个顺序进行搜索。在装包过程中,要尽量优先选择价值重量比较高的物品装入背包。表现在搜索过程中,就是要尽量沿着左子树结点前进。当不能继续前进时(假设该结点为T),就得到问题的一个部分解,并把搜索转移到右子树。估计由该部分解所能得到的最大价值,即结点T的上限。可以用贪婪算法处理剩余物品:将按照价值重量比非增顺序排列的剩余物品依次装入背包,至无法完全装入下一个物品时,就将该物品的一部分装满背包。这样就可以得到一个上限。如果该值为当前最优值:继续由右子树向下搜索,扩大部分解,直至找到可行解;保存可行解,并把可行解的值作为当前最优值,向上回溯,寻找其他可行解;若该值小于当前最优值:丢弃当前正在搜索的部分解,向上回溯。反复使用此方法,直至搜索完整个解空间。

(2)回溯算法求解0-1背包问题示例:

给定8种物品和一个背包。8种物品的重量和价值分别为(79,83)、(58,14)、(86,54)、(11,79)、(28,72)、(62,52)、(15,48)、(68,62),背包的容量为200。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

一种可能的解决方案是(红色字体强调突出的物品):(79,83)、(58,14)、(86,54)、

(11,79)、(28,72)、(62,52)、(15,48)、(68,62);装入背包中的物品的总价值为334。

(3)回溯算法求解0-1背包问题的源代码(供参考)

算法步骤如下:

1)按价值重量比的非增顺序排列物品。

2)初始化:当前背包重量tempW为0,当前背包中物品总价值tempV为0,当前搜索深度i为0,当前解向量为x[i]=0,当前最优值maxV为0。

3)调用限界函数。

4)如果返回的上限大于当前最优值maxV,从物品Pi开始把物品装入背包,直至没有物品可装或装不下物品Pk为止,并生成部分解,转步骤5);否则,转步骤6)。

5)如果k大于或等于物品总数量n,则得到一个可行解,并把该可行解的值作为当前最优值,令i=n,转步骤3),以便回溯搜索其他可行解;否则,令i=k+l,拒绝物品k,从物品k+l继续装入,转步骤3)。

6)当k≥0且x[k]=0时,令k=k-1,直至条件不成立。即沿着右分支结点方向向上回溯,直至左分支结点。

7)如果k<0,算法结束;否则,转步骤8)。

8)令x[k]=0,tempW=tempW-w[k],tempV=tempV-v[k],i=k+l,转步骤3)。

/*回溯法解0-1背包问题*/

#define N 8// 物品个数

#define C 200 //容积

int result[N]; //存储结果:0表示不在集合内,1表示在集合内

int tempR[N]; //当前结果

int w[N]; //重量

int v[N]; //价值

int tempV = 0; //当前价值

int maxV = 0 ; //最大价值

int tempW = 0 ; //当前的容量

void traceBack(int i )

{

if(i>=N){

if(tempV>maxV){

maxV = tempV;

int j = 0;

for(j=0;j

result[j] = tempR[j];

}

}

return;

} //边界情况考虑

相关文档
最新文档