算法设计与分析 第八章分枝限界法Word格式.docx
《算法设计与分析 第八章分枝限界法Word格式.docx》由会员分享,可在线阅读,更多相关《算法设计与分析 第八章分枝限界法Word格式.docx(17页珍藏版)》请在冰豆网上搜索。
2).优先队列式分枝限界法:
将活结点表组织成一个优先队列,并按优先队列给结点规定的优先级选取优先级最高的下一个结点作为当前扩展结点。
队列式分枝限界法搜索解空间树的方式类似于解空间树的宽度优先搜索,不同的是队列式分枝限界法不搜索不可行结点(已经被判定不能导致可行解或不能导致最优解的结点)为根的子树。
这是因为,按照规则,这样的结点未被列入活结点表。
优先队列式分枝限界法的搜索方式是根据活结点的优先级确定下一个扩展结点。
结点的优先级常用一个与该结点有关的数值p来表示。
最大优先队列规定p值较大的结点的优先级较高。
在算法实现时通常用一个最大堆来实现最大优先队列,用最大堆的Deletemax运算抽取堆中的下一个结点作为当前扩展结点,体现最大效益优先的原则。
类似地,最小优先队列规定p值较小的结点的优先级较高。
在算法实现时,常用一个最小堆来实现,用最小堆的Deletemin运算抽取堆中下一个结点作为当前扩展结点,体现最小优先的原则。
采用优先队列式分枝限界算法解决具体问题时,应根据问题的特点选用最大优先或最小优先队列,确定各个结点的p值。
例1.1旅行商问题,n=4,其解空间树是一棵排列树。
如文档“旅行商搜索树”。
赋权图G给出如下:
采用队列式分枝限界法以排列树中的结点B作为初始扩展结点。
此时,活结点队列为空。
由于从图G的顶点1到顶点2、3和4均有边相连,B的儿子C、D和E都是可行结点,它们被依次加入到活结点队列中,并舍弃当前扩展结点B。
当前活结点队列中的队首结点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,3,1),费用仍为25。
此后的两个扩展结点是K和I。
由结点K得到的Hamilton圈的费用高于当前所知最小费用,结点I当前的费用已经高于当前所知最小费用,因而,它们都不能得到最优解。
最后,优先队列为空,算法终止。
对于优化问题,要记录一个到目前已经取得的最优可行解及对应的目标函数值,这个记录要根据最优的原则更新。
无论采用队列式还是优先队列搜索,常常用目标函数的一个动态界(函数)来剪掉不必要搜索的分枝。
对于最大值优化问题,常引用一个可能获得的目标函数值的一个上界CUB(经此结点可能达到的最大“效益值”)。
如果当前扩展结点的儿子结点处的动态上界CUB不大于目前所取得的目标函数值f,则该儿子结点不被放入结点序列。
实际上相当于剪掉了以该儿子结点为根的子树。
对于最小值优化问题,常引用一个可能出现的目标函数值的一个下界CLB(经此结点可能出现的最小“消费”),如果当前扩展结点的儿子结点处的动态下界CLB不小于目前所取得的目标函数值f,则该儿子结点不被放入结点序列。
上述动态界称为剪枝函数,采用剪枝函数可以减少活结点数,降低搜索过程的复杂度。
20/1背包问题的分枝-限界法
用优先队列式分枝限界法解决0/1背包问题(作为极大化问题),需要确定以下四个问题:
解空间树中结点的结构、如何生成一个给定结点的儿子、如何组织活结点表、如何识别答案结点。
我们采用完整的二叉树作为解空间树,放在活结点表中的每个结点具有6个信息段:
Parent、Level、Tag、CC、CV、CUB。
其中Parent是结点X的父亲结点连接指针;
Level标志出结点X在解空间树中的级数,通过置
表示生成X的左儿子,置
表示生成X的右儿子;
信息段Tag用来输出最优解各个分量
的值;
信息段CC记录背包在结点X处的可用空间(即剩余空间),在确定X左儿子的可行性时用;
CV记录在结点X处背包中已装物品的价值(或效益值),等于
;
信息段CUB用来存放结点X的Pvu值。
这里,Pvu表示在结点X所表示的状态下,可行解所能达到的可能值的上界。
也即是说,当
的值确定后,可行解
所能达到的效益值的上界。
类似地,当
所能达到的最大效益值的下界记做Pvl。
如果到目前为止所知道的可行解的最大效益值CV不小于Pvl,则当Pvu<
CV时,就应该杀死结点X。
所以,Pvu(X)可以作为限界函数和优先级函数。
关于它们的计算将由一个子程序给出。
作为极大化问题处理的优先队列式分枝限界法解0/1背包问题的程序LCKNAP采用了六个子程序:
LUBound、NewNode、Finish、Init、GetNode和Largest。
子程序LUBound计算Pvl和Pvu之用;
NewNode生成一个具有六个信息段的结点,给各个信息段置入适当的值,并将此结点加入结点表;
Finish打印出最优解的值和此最优解中
的物品;
Init对可用结点表和活结点表置初值;
GetNode取一个可用结点;
Largest在活结点表中取一个具有最大Pvl值结点作为下一个扩展结点。
程序8-2-10/1背包问题的优先队列式分枝限界算法
LCKNAP(P,W,M,N,)//假定物品的排列顺序遵循P[i]/W[i]P[i+1]/W[i+1];
realP[1:
N],W[1:
N],M,CL,Pvl,Pvu,cap,prof;
integerANS,X,N;
1.Init;
//初始化可用结点表及活结点表
2.GetNode(E);
//生成根结点
3.Parent(E)=0;
Level=1;
CC(E)=M;
CV(E)=0;
4.LUBound(P,W,M,0,N,1,Pvl,Pvu);
5.CV=Pvl-;
CUB(E)=Pvu;
6.Loop
7.i=Level(E);
cap=CC(E);
prof=CV(E);
8.case
9.:
i=N+1:
//解结点
10.ifprof>
CVthen
11.CV=prof;
ANS=E;
12.endif
13.:
else:
//E是内部结点,有两个儿子
14.ifcapW[i]then//左儿子可行
15.NewNode(E,i+1,1,cap-W[i],prof+P[i],CUB(E));
16.endif
17.LUBound(P,W,cap,prof,N,i+1,Pvl,Pvu);
18.ifPvu>
CVthen//右儿子会活
19.NewNode(E,i+1,0,cap,prof,Pvu);
CV=max(CV,Pvl-);
20.endif
21.endcase
22.if不再有活结点thenexitendif
23.Largest(E);
//取下一个扩展结点
24.untilCUB(E)CVendloop
25.Finish(CV,ANS,N);
26.endLCKNAP
算法中有两点值得注意:
(1).第6~24行的循环依次检查所生成的每个结点。
此循环在以下两种情况下终止:
或者活结点队列为空,或者为了扩展而选择的结点E(扩展结点)满足CUB(E)CV.在后一种情况下,由扩展结点的选法可知,对所有的扩展结点X均有CUB(X)CUB(E)CV,因而它们都不能导致其值比CV更大的解。
(2).在左儿子X可行的情况下,由LUBound算出它的上界,并由此而得CUB(X)=CUB(E).因为CUB(E)>
CV或者CV=Pvu-<
Pvu,所以将X加入活结点表。
由于左儿子的下界、上界与E的相同,因而不必再计算。
但是右儿子则不同,所以需要调用函数LUBound来获取CUB(Y)=Pvu.如果PvuCV,则杀死结点Y(即,不放在结点表中)。
否则,将结点Y加入活结点表,并修改CV的值(第19行)。
以下附上前面提到的几个子程序。
程序8-2-2计算结点状态下的可能取得最大效益值的上、下界
LUBound(P,W,rw,cp,N,k,Pvl,Pvu)//rw是背包的剩余容量,cp是已取得的效益值,还有物品k,…,N要考虑
Pvl=cp;
c=rw;
forifromktoNdo
ifc<
W[i]thenPvu=Pvl+c*P[i]/W[i];
//从第k件到第N件至少有一件物品不能装进背包的情形出现
forjfromi+1toNdo
ifcW[j]then
c=c-W[j];
Pvl=Pvl+P[j];
endif
endfor
return//此时Pvl<
Pvu
endif
c=c-W[i];
Pvl=Pvl+P[i];
Pvu=Pvl;
//从第k件物品到第N件物品都能装进背包的情形出现,
endLUBound
程序8-2-3程序生成新结点算法
NewNode(par,lev,t,cap,prof,ub)//生成一个新结点J,并把它加到//活结点表
GetNode(J);
Parent(J)=par;
Level(J)=lev