算法设计与分析讲义-中科院-陈玉福ch8
- 格式:pdf
- 大小:296.95 KB
- 文档页数:21
154 第八章 分枝-限界法 §1 算法基本思想 分枝限界法同回溯法类似,它也是在解空间中搜索问题的可行解或最优解,但搜索的方式不同。回溯法采用深度优先的方式,朝纵深方向搜索,直至达到问题的一个可行解,或经判断沿此路径不会达到问题的可行解或最优解时,停止向前搜索,并沿原路返回到该路径上最后一个还可扩展的节点。然后,从该节点出发朝新的方向纵深搜索。分枝限界法则采用宽度优先的方式搜索解空间树,它将活节点存放在一个特殊的表中。其策略是:在扩展节点处,首先生成其所有的儿子节点,将那些导致不可行解或导致非最优解的儿子舍弃,其余儿子加入活节点表中。然后,从活节点表中取出一个节点作为当前扩展节点,重复上述节点扩展过程。 分枝限界法与回溯法的本质区别在于搜索方式的不同。回溯法更适于处理那些寻求所有可行解的问题,而分枝限界法更适于处理求最优解的问题。从活节点表中选择下一扩展节点的不同方式导致不同的分枝限界法。最常见的有以下两种方式: 1). 队列式(FIFO)分枝限界法: 这种方式是将活节点表组织成一个队列,并按队列的先进先出原则选取下一个节点作为当前扩展节点。 2). 优先队列式分枝限界法: 这种方式是将活节点表组织成一个优先队列,并按优先队列给节点规定的优先级选取优先级最高的下一个节点作为当前扩展节点。 队列式分枝限界法搜索解空间树的方式类似于解空间树的宽度优先搜索,不同的是队列式分枝限界法不搜索不可行节点(已经被判定不可能导致可行解或不可能导致最优解的节点)为根的子树。为达此目的,算法不把这样的节点列入活节点表。 优先队列式分枝限界法的搜索方式是根据活节点表中节点的优先级确定下一个扩展节点。节点的优先级常用一个与该节点有关的数值p来表示。最大优先队列规定p值较大的节点的优先级较高。在算法实现时通常用一个最大堆来实现最大优先队列,用最大堆的Deletemax运算抽取堆中的下一个节点作为当前扩展节点,体现最大效益优先的原则。类似地,最小优先队列规定p值较小的节点的优先级较高。在算法实现时,常用一个最小堆来实现,用最小堆的Deletemin运算抽取堆中下一个节点作为当前扩展节点,体现最小优先的原则。采用优先队列式分枝限界算法解决具体问题时,应根据问题的特点选用最大优先或最小优先队列,确定各个节点的p值。 155例1.1 旅行商问题,n=4,其解空间树是一棵排列树。如文档“旅行商搜索树”。赋权图G给出如下:
图8-1-1 一个表示旅行商问题的赋权图 采用队列式分枝限界法以排列树中的节点B作为初始扩展节点,此时,活节点队列为空。由于从图G的顶点1到顶点2、3和4均有边相连,B的儿子C、D和E都是可行节点,它们被依次加入到活节点队列中。当前活节点队列中的队首节点C成为下一个扩展节点。由于图G的顶点2到顶点3和4有边相连,故节点C的二个儿子F和G均为可行节点,可以加入活节点队列。接下来,节点D和节点E相继成为扩展节点。此时活节点队列中的节点依次为F、G、H、I、J、K。节点F成为下一个扩展节点,但其儿子L是解空间树的叶节点,我们找到了一条Hamilton圈(1,2,3,4,1),其费用为59。此时记录这个目标函数值 f=59。下一个扩展节点G的儿子M也是叶节点,得到另一条Hamilton圈(1,2,4,3,1),其费用为66。节点H成为当前扩展节点,其儿子N也是叶节点,得到第三条Hamilton圈,其费用为25,因为它比记录中的目标函数值还小,所以修改目标函数值记录:f=25。下一个扩展节点是I,由于从根节点到节点I的费用26已经超过目标函数的当前值,故没有必要扩展I,以I为根的子树被剪掉。最后J和K被依次扩展,活节点队列成为空集,算法终止。算法搜索到的最优值是25,相应的最优解是从根节点到节点N的路径 (1,3,2,4,1)。 采用优先队列式分枝限界法,用一个最小堆存储活节点表,优先级函数值是节点的当前费用。算法还是从排列树的节点B和空队列开始。节点B被扩展后,它的3个儿子C、D和E被依次插入堆中。此时,由于E是堆中具有最小当前费用(为4)的节点,所以处于堆顶的位置,它自然成为下一个扩展节点。节点E被扩展后,其儿子J和K被插入当前堆中,它们的费用分别为14和24。此时,堆顶元素是D,它成为下一个扩展节点。它的2个儿子H和I被插入堆中。此时,堆中元素是节点C、H、I、J、K。在这些节点中,H具有最小费用,成为下一个扩展节点。扩展节点H后得到一条Hamilton圈(1,3,2,4,1),相应的费用为25。接下来,节点J成为扩展节点,并由此得到一条Hamilton圈(1,4,2,
1 423 30
求赋权图G的 具有最小权的 Hamilton圈 6
5
41020 156 3,1),费用仍为25。此后的两个扩展节点是K和I。由节点K得到的Hamilton圈的费用高于当前所知最小费用,节点I当前的费用已经高于当前所知最小费用,因而,它们都不能得到最优解。最后,优先队列为空,算法终止。 对于优化问题,要记录一个到目前已经取得的最优可行解及对应的目标函数值,这个记录要根据最优的原则更新。无论采用队列式还是优先队列式搜索,常常用目标函数的一个动态界(函数)来剪掉不必要搜索的分枝。 对于最大值优化问题,常引用一个可能获得的目标函数值的一个上界CUB(经此节点可能达到的最大“效益值”)。如果当前扩展节点的儿子节点处的动态上界CUB小于目前所取得的目标函数值prev,则该儿子节点不被放入节点表。实际上相当于剪掉了以该子节点为根的子树。 对于最小值优化问题,常引用一个可能出现的目标函数值的一个下界CLB(经此节点可能出现的最小“消费”),如果当前扩展节点的儿子节点处的动态下界CLB大于目前所取得的目标函数值prev,则该子节点不被放入活节点队列。上述动态界称为剪枝函数,采用剪枝函数可以减少活节点数,降低搜索过程的复杂度。
§2 0/1背包问题的分枝-限界法 用优先队列式分枝限界法解决0/1背包问题(作为最大优化问题),需要确定以下四个问题: i. 解空间树中节点的结构; ii. 如何生成一个给定节点的儿子; iii. 如何组织活节点表; iv. 如何识别答案节点。 我们采用完整的二叉树作为解空间树,放在活节点表中的每个节点具有6个信息段: Parent、Level、Tag、CC、CV、CUB 其中Parent是节点X的父亲节点连接指针;Level标出节点X在解空间树中的
深度,通过置表示生成X的左儿子,置()11LevelXX+=()10LevelXX+=表示生成X的右
儿子;信息段Tag用来输出最优解各个分量的值;信息段CC记录背包在节点X处的可用空间(即剩余空间),在确定X左儿子的可行性时用;CV记录在节点X处背包中已装物品的价值(或效益值),等于ix
1()iiiLevelXpx≤≤
∑;信息段CUB用来存放
节点X的Pvu值。这里,Pvu表示在节点X所表示的状态下,可行解所能达到的可能价值的一个上界。也即是说,当11,,,llxxx−"的值确定后,可行解 15711,,,,,llnxxxx+"" 所能达到的效益值的上界。类似地,当11,,,llxxx−"的值确定
后,可行解11,,,,,llnxxxx+"" 所能达到的效益值的最大下界记做prev,Pvl是
到目前为止所找到的解的最好目标值与当前能够探测到解的目标值的一个最大下界。如果节点X满足Pvu当Pvu = prev 时要谨慎处理(因为在程序执行过程中,贸然杀死该节点可能使最优解夭折了)。如果将prev用Pvl-ε(ε是一个充分小的正数)、prev两者中的最大者来替换,则采用规则: 当Pvu ≤ prev时杀死节点X 能够杀死更多的不必要搜索的节点。所以,Pvu(X)可以作为优先级函数,而prev可以作为限界函数。关于它们的计算将由一个子程序给出。 作为求最大值优化问题处理的优先队列式分枝限界法解0/1背包问题的程序LCKNAP采用了六个子程序:LUBound、NewNode、Finish、Init、GetNode和Largest。子程序LUBound计算Pvl和Pvu之用;NewNode生成一个具有六个信息段的节点,给各个信息段置入适当的值,并将此节点加入节点表;Finish打
印出最优解的值和此最优解中1=ix的物品;Init对可用节点表和活节点表置初值;GetNode取一个可用节点;Largest在活节点表中取一个具有最大Pvu值节点作为下一个扩展节点。
程序8-2-1 0/1背包问题的优先队列式分枝限界算法 proc LCKNAP(P,W,M,N)//假定物品的排列顺序遵循 P[i]/W[i]≥ //P[i+1]/W[i+1]; real P[1..N],W[1..N],M,CL,Pvl,Pvu,cap,cv,prev; integer ANS,X,N; 1. Init;//初始化可用节点表及活节点表 2. GetNode(E);//生成根节点 3. Parent(E):=0; Level(E):=0; CC(E):=M; CV(E)=0; 4. LUBound(P,W,M,0,N,1,Pvl,Pvu); 5. prev:=Pvl-ε; CUB(E):=Pvu; Tag(E):=0; 6. Loop 7. i:=Level(E)+1, cap:=CC(E), cv:=CV(E); 8. case: 9. i=N+1: //解节点 10. if cv>prev then 11. prev:=cv; ANS:=E;