算法设计与分析 第八章分枝限界法.docx
- 文档编号:25213218
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:20
- 大小:111.16KB
算法设计与分析 第八章分枝限界法.docx
《算法设计与分析 第八章分枝限界法.docx》由会员分享,可在线阅读,更多相关《算法设计与分析 第八章分枝限界法.docx(20页珍藏版)》请在冰豆网上搜索。
算法设计与分析第八章分枝限界法
第八章分枝-限界法
§1算法基本思想
本章叙述中为了区别图中的顶点和解空间树中的顶点,凡是在解空间树中出现的“顶点”一律称为“结点”。
分枝限界法同回溯法类似,它也是在解空间中搜索问题的可行解或最优解,但搜索的方式不同。
回溯法采用深度优先的方式,朝纵深方向搜索,直至达到问题的一个可行解,或经判断沿此路径不会达到问题的可行解或最优解时,停止向前搜索,并沿原路返回到该路径上最后一个还可扩展的结点。
从该结点出发朝新的方向纵深搜索。
分枝限界法则采用宽度优先的方式搜索解空间树,它将活结点存放在一个特殊的表中。
其策略是:
在扩展结点处,首先生成其所有的儿子结点,将那些导致不可行解或导致非最优解的儿子舍弃,其余儿子加入活结点表中。
然后,从活结点表中取出一个结点作为当前扩展结点。
重复上述结点扩展过程。
所以,分枝限界法与回溯法的本质区别在于搜索方式的不同。
回溯法更适于处理那些求所有可行解的问题,而分枝限界法更适于处理那些只确定一个可行解,特别是最优解的问题。
从活结点表中选择下一扩展结点的不同方式导致不同的分枝限界法。
最常见的有以下两种方式:
1).队列式(FIFO)分枝限界法:
将活结点表组织成一个队列,并按队列的先进先出原则选取下一个结点作为当前扩展结点。
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 所以,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.: ,有两个儿子 14.ifcap≥W[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-ε 由于左儿子的下界、上界与E的相同,因而不必再计算。 但是右儿子则不同,所以需要调用函数LUBound来获取CUB(Y)=Pvu.如果Pvu≤CV,则杀死结点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 //从第k件到第N件至少有一件物品不能装进背包的情形出现 forjfromi+1toNdo ifc≥W[j]then c=c-W[j];Pvl=Pvl+P[j]; endif endfor return//此时Pvl endif c=c-W[i];Pvl=Pvl+P[i]; endfor Pvu=Pvl;//从第k件物品到第N件物品都能装进背包的情形出现, endLUBound 程序8-2-3程序生成新结点算法 NewNode(par,lev,t,cap,prof,ub)//生成一个新结点J,并把它加到//活结点表 GetNode(J); Parent(J)=par;Level(J)=lev;Tag(J)=t; CC(J)=cap;CV(J)=prof;CUB(J)=ub; Add(J); endNewNode 程序8-2-4打印答案程序 Finish(CV,ANS,N)//输出解 realCV;globalTag,Parent; print(‘OBJECTSINKNAPSACKARE’) forjfromNby–1to1do ifTag(ANS)=1then print(j); endif ANS=Parent(ANS); endfor endFinish §3电路板布线问题 印刷电路板将布线区域分成n×m个方格阵列,如下图(a).精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。 在布线时,电路只能沿直线或直角布线,如下图(b)所示。 为了避免线路相交,已布了线的方格做了封锁标记,其它线路不允许穿过被封锁的方格。 采用队列式(FIFO)分枝限界法解此问题,它的解空间树是一个无向图。 首先结点a作为第一个扩展结点。 与该扩展结点相邻并且可达的方格成为可行结点被加入到活结点队列,这些结点被加入队列的顺序是: 右、下、左、上。 将这些方格标记为1,它表示从起始方格a到这些方格的距离为1。 接着从活结点队列中取出队首结点作为下一个扩展结点,并将与扩展结点相邻且未标记过的方格标记为2,并以右、下、左、上的顺序将这些结点存放到活结点队列中。 这个过程一直持续到算法搜索到目标方格b或者活结点队列为空时停止。 注意到,搜索过程在遇到标记封锁的方格时,自动放弃此方格。 下图是在7×7方格阵列中布线的例子。 其中,起始点的位置是a=(3,2),目标是位置b=(4,6).有! ! 号的方格表示被封锁。 搜索过程如下图(c)所示。 图(c)图(d) 本例中,a到b的最短距离是9。 要构造出与最短距离相应的最短路径,须从目标方格开始向起始方格回溯,逐步构造出最优解。 每次向比当前方格标号小1的相邻方格移动,直至到达起始方格为止。 图(d)给出了该例子的最短路径,它是从目标方格b移动到(5,6),然后移至(6,6),…,最终移至起始方格a。 在算法实现时,首先定义一个表示电路板上方格位置的类Position,它有两个私有成员row和col,分别表示方格所在的行和列。 在电路板的任一方格处,布线可沿右、下、左、上四个方向进行,分别记为移动0,1,2,3。 offset[i].col=1表示向右前进一步;offset[i].col=-1表示向左前进一步。 在这两种情况下,都有,offset[i].row=0。 类似地讨论向下和向上前进的情况。 一般用一个二维数组grid表示所给的方格阵列。 初始时,grid[i][j]=0,表示该方格允许布线,而grid[i][j]=1表示该方格不允许布线(有封锁标记)。 为了便于处理边界方格的情况,算法对所给的方格阵列的四周设置一道“围墙”,即增设标记为1的附加方格。 算法开始时测试初始方格与目标方格是否相同。 若相同,则不必计算,直接返回最短距离0。 否则,算法设置方格阵列的围墙,初始化位移矩阵offset。 算法将起始位置的距离记为2。 因为数字0和1用于表示方格的开放或封闭状态,所以,表示距离不用这两个数字,因而将所有的距离值都加2。 实际距离应为标记距离减2。 算法从起始位置start开始,首先标记所有标记距离为3的方格,并存入活结点队列,然后依次标记所有标记距离为4,5,…的方格,直至到达目标方格finish或活结点队列为空时为止。 程序8-3-1布线问题的队列式分枝限界算法 boolFindPath(Positionstart,Positionfinish,int&PathLen, Position*&path) {//计算从起点位置start到目标位置finish的最短布线路径,找到最短布线路//径则返回true,否则返回false if((start.row==finish.row)&&(start.col==finish.col) {PathLen=0;returntrue;}//start=finish //设置方格阵列“围墙” for(inti=0;i<=m+1;i++) grid[0][i]=grid[n+1][i]=1;//顶部和底部 for(inti=0;i<=n+1;i++) grid[i][0]=grid[i][m+1]=1;//左翼和右翼 //初始化相对位移 Positionoffset[4]; offset[0].row=0;offset[0].col=1;//右 offset[1].row=1;offset[1].col=0;//下 offset[2].row=0;offset[2].col=-1;//左 offset[3].row=-1;offset[3].col=0;//上 intNumOfNbrs=4;//相邻方格数 Positionhere,nbr; Here.row=start.row; Here.col=start.col; Grid[start.row][start.col]=2; //标记可达方格位置 LinkedQueue Do{//标记相邻可达方格 For(intI=0;I Nbr.row=here.row+offset[I].row; Nbr.col=here.col+offset[I].col; If(grid[nbr.row][nbr.col]==0){ //该方格未被标记 grid[nbr.row][nbr.col]=grid[here.row][here.col]+1; if((nbr.row==finish.row)&& (nbr.col==finish.col))break;//完成布线 Q.Add(nbr);} } //是否到达目标位置finish? If((nbr.row==finish.row) (nbr.col==finish.col))break;//完成布线 //活结点队列是否非空? If(Q.IsEmpty())returnfalse;//无解 Q.Delete(here);//取下一个扩展结点 }while(true); //构造最短布线路径 PathLen=grid[finish.row][finish.col]-2; path=newPosition[PathLen]; //从目标位置finish开始向起始位置回溯 here=finish; for(intj=PathLen-1;j>=0;j--){ path[j]=here; //找前驱位置 for(inti=0;i nbr.row=here.row+offset[i].row; nbr.col=here.col+offset[i]; if(grid[nbr.row][nbr.col]==j+2)break; } here=nbr;//向前移动 } returntrue; } 由于每个方格成为活结点进入活结点队列最多1次,活结点队列中最多只处理O(mn)个活结点。 扩展每个活结点需要O (1)时间,因此共耗时O(mn)。 构造相应的最短距离需要O(L)时间,其中,L是最短路径的长度。 作业: 1.假设旅行商问题的邻接矩阵为 试采用优先队列式分枝限界算法给出最短环游。 画出解空间树搜索图,并说明搜索过程。 2.试写出0/1背包问题的优先队列式分枝限界算法程序,并找一个物品件数为16的例子检验程序的运行情况。 §4优先级的确定与LC-检索 对于优先队列式分枝限界法,结点优先级的确定直接影响着算法性能。 我们当然希望具有下列特征的活结点X成为当前扩展结点: 1).以X为根的子树中含有问题的答案结点; 2).在所有满足条件1)的活结点中,X距离答案结点“最近”。 但是,要给可能导致答案结点的活结点附以优先级,必须要附加若干计算工作,即要付出代价。 对于任一结点,要付出的代价可以使用两种标准来度量: (i).在生成一个答案结点之前,子树X需要生成的结点数; (ii).以X为根的子树中,离X最近的那个答案结点到X的路径长度。 容易看出,如果使用度量(i),则对于每一种分枝限界算法,总是生成最小数目的结点;如果采用度量(ii),则要成为扩展结点的结点只是那些由根到最近的那个答案结点路径上的那些结点。 用c(·)表示一个理想的优先级函数,递归地定义如下: a).如果X是答案结点,则c(X)是解空间树中由根结点到X的成本(即所用的代价,如级数、计算复杂度等); b).如果X不是答案结点,而且以X为根的子树中不含答案结点,则c(X)定义为∞; c).如果X不是答案结点,但是以X为根的子树中含答案结点,则c(X)是具有最小成本的答案结点的成本。 如果能够获得这样的优先级函数,则优先队列式分枝限界法将以最少的搜索时间找到问题的解。 然而,这样的优先级函数的计算工作量有时不亚于解原问题。 实际问题中都是采用一个估计函数ĉ,它由两部分决定: 解空间树的根结点到X的成本f(X),以及由X到答案结点的估计成本g(X)。 ĉ(X)=f(X)+g(X),ĉ称为成本估计函数。 根据成本估计函数选择下一个扩展结点的策略总是选取ĉ(·)值最小的活结点作为下一个扩展结点。 这种搜索策略称为最小成本检索(LeastCostSearch),简称LC-检索。 如果取g=0且f(X)等于X在解空间树中的级,则LC-检索即是宽度优先搜索(BFS);如果f=0,而且g满足: Y是X的儿子⇒g(Y)≤g(X)( 则LC-检索即是深度优先搜索(DFS).在以后所提到的成本函数ĉ中,函数g都满足( 例子4.115迷问题 在一个分成4×4的棋盘上排列15块号牌,如图(a)。 其中会出现一个空格。 棋盘上号牌的一次合法移动是指将位于空格上、下、左、右的一块号牌移入空格。 要求通过一系列合法移动,将号牌的初始排列转换成自然排列,如图(b). 图(a)图(b)图(c) 如果将棋盘的各个位置按照号牌的自然排列发给序号,右下角发给16号。 则号牌的每一种排列都可以看作是1,…,15,16这16个数的排列,其中,16的位置代表空格。 如图(a)对应的排列是(1,3,4,15,2,16,5,12,7,6,11,14,8,9,10,13).事实上,不是号牌的每一种排列都能够经过一系列合法移动转换成自然排列的。 用Less(i)记排列P中位于i后面且号码比i小的号牌个数,则排列P可以经一系列合法移动转换成自然排列的充要条件是 是偶数( 其中,当空格在图(c)的某个#位置时,X=1;否则X=0.以后记 称为排列P的逆序数。 例如,图(a)中排列的逆序数为16,X=0,所以图(a)中排列可经一系列合法移动转换成自然排列。 在处理实际问题中,一般是根据具体问题的特性,确定成本估价函数ĉ(X)=f(X)+g(X)中的函数f(X)和g(X).在本例中,我们令f(x)是由根到结点X的路径的长度,g(X)是以X为根的子树中,由X到目标状态(自然排列)的一条最短路径长度的估计值。 为此,g(X)至少应是把状态X转换成目标状态所需的最少移动数目。 对它的一种可能的选择是 g(X)=排列X的不在自然位置的牌的数目( 图(a)的排列中,不在自然位置的牌号分别是: 3,4,15,2,5,12,7,6,14,8,9,10,13,共13个。 g(X)=13.将图(a)中的排列转换成自然排列至少需要13次合法的移动。 可见,成本估价函数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法设计与分析 第八章分枝限界法 算法 设计 分析 第八 分枝 限界