计算机算法设计与分析-第6章剖析优秀PPT.ppt
1第6章 分支限界法2学习要点学习要点理解分支限界法的剪枝搜寻策略。理解分支限界法的剪枝搜寻策略。驾驭分支限界法的算法框架驾驭分支限界法的算法框架(1)队列式)队列式(FIFO)分支限界法分支限界法(2)优先队列式分支限界法)优先队列式分支限界法 通过应用范例学习分支限界法的设计策略。通过应用范例学习分支限界法的设计策略。(1)单源最短路径问题)单源最短路径问题(2)装载问题;)装载问题;(3)布线问题)布线问题(4)0-1背包问题;背包问题;(5)最大团问题;)最大团问题;(6)旅行售货员问题)旅行售货员问题(7)电路板排列问题)电路板排列问题(8)批处理作业调度问题)批处理作业调度问题36.1 分支限界法的基本思想分支限界法与回溯法(1)求解目标:回溯法的求解目标是找出解空间树中满足约束条件的全部解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。(2)搜寻方式的不同:回溯法以深度优先的方式搜寻解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜寻解空间树。46.1 分支限界法的基本思想分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜寻问题的解空间树。此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程始终持续到找到所需的解或活结点表为空时为止。在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其全部儿子结点。在这些儿子结点中,导致不行行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。56.1 分支限界法的基本思想常见的两种分支限界法(1)队列式(FIFO)分支限界法依据队列先进先出(FIFO)原则选取下一个节点为扩展节点。(2)优先队列式分支限界法依据优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。FIFO 及优先队列FIFOAB,CC,D,ED,E,F,G E,F,G,H,I w1=16w2=15w3=15背包涵量 c=30物品价值 p=45,25,25物品重量 w=16,15,15优先队列AB(40),C(0)D(notf),E(notf),CF(25),G(25)76.2 单源最短路径问题1.问题描述 下面以一个例子来说明单源最短路径问题:在下图所给的有向图G中,每一边都有一个非负边权。要求图G的从源顶点s到目标顶点t之间的最短路径。o86.2 单源最短路径问题1.问题描述下图是用优先队列式分支限界法解有向图G的单源最短路径问题产生的解空间树。其中,每一个结点旁边的数字表示该结点所对应的当前路长。96.2 单源最短路径问题2.算法思想解单源最短路径问题的优先队列式分支限界法用一微小堆来存储活结点表。其优先级是结点所对应的当前路长。算法从图G的源顶点s和空优先队列起先。结点s被扩展后,它的儿子结点被依次插入堆中。此后,算法从堆中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的全部顶点。假如从当前扩展结点i到顶点j有边可达,且从源动身,途经顶点i再到顶点j的所相应的路径的长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。这个结点的扩展过程一干脆着到活结点优先队列为空时为止。106.2 单源最短路径问题3.剪枝策略 在算法扩展结点的过程中,一旦发觉一个结点的下界不小于当前找到的最短路长,则算法剪去以该结点为根的子树。在算法中,利用结点间的限制关系进行剪枝。从源顶点s动身,2条不同路径到达图G的同一顶点。由于两条路径的路长不同,因此可以将路长长的路径所对应的树中的结点为根的子树剪去。116.2 单源最短路径问题/initialize E.i=v,E.length=0,distv=0;while(true)for(int j=1;j=n;j+)if(cE.ijinf)&(E.length+cE.ijdistj)/distj初始化为MaxInt /顶点i到顶点j可达,且满足限制约束 distj=E.length+cE.ij;prevj=E.i;/加入活结点优先队列 MinHeapNode N;N.i=j;N.length=distj;H.Insert(N);try H.DeleteMin(E);/取下一扩展结点 catch(OutOfBounds)break;/优先队列空 顶点点I和和j间有有边,且此路,且此路径径长小于原先从原点到小于原先从原点到j的路径的路径长 126.3 装载问题1.问题描述有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船,其中集装箱i的重量为Wi,且装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。假如有,找出一种装载方案。简洁证明:假如一个给定装载问题有解,则接受下面的策略可得到最优装载方案。(1)首先将第一艘轮船尽可能装满;(2)将剩余的集装箱装上其次艘轮船。136.3 装载问题2.队列式分支限界法在算法的while循环中,首先检测当前扩展结点的左儿子结点是否为可行结点。假如是则将其加入到活结点队列中。然后将其右儿子结点加入到活结点队列中(右儿子结点确定是可行结点)。2个儿子结点都产生后,当前扩展结点被舍弃。活结点队列中的队首元素被取出作为当前扩展结点,由于队列中每一层结点之后都有一个尾部标记-1,故在取队首元素时,活结点队列确定不空。当取出的元素是-1时,再推断当前队列是否为空。假如队列非空,则将尾部标记-1加入活结点队列,算法起先处理下一层的活结点。146.3 装载问题2.队列式分支限界法while(true)/检查左儿子结点 if(Ew+wi=c)/xi=1 EnQueue(Q,Ew+wi,bestw,i,n);/右儿子结点总是可行的 EnQueue(Q,Ew,bestw,i,n);/xi=0 Q.Delete(Ew);/取下一扩展结点 if(Ew=-1)/同层结点尾部 if(Q.IsEmpty()return bestw;Q.Add(-1);/同层结点尾部标记 Q.Delete(Ew);/取下一扩展结点 i+;/进入下一层 156.3 装载问题3.算法的改进节点的左子树表示将此集装箱装上船,右子树表示不将此集装箱装上船。设bestw是当前最优解;ew是当前扩展结点所相应的重量;r是剩余集装箱的重量。则当ew+rbestw时,可将其右子树剪去,因为此时若要船装最多集装箱,就应当把此箱装上船。另外,为了确保右子树成功剪枝,应当在算法每一次进入左子树的时候更新bestw的值。166.3 装载问题3.算法的改进/检查左儿子结点 Type wt=Ew+wi;/左儿子结点的重量 if(wt bestw)bestw=wt;/加入活结点队列 if(i bestw&i n)Q.Add(Ew);/可能含最优解 Q.Delete(Ew);/取下一扩展结点右儿子剪枝右儿子剪枝 176.3 装载问题4.构造最优解为了在算法结束后能便利地构造出与最优值相应的最优解,算法必需存储相应子集树中从活结点到根结点的路径。为此目的,可在每个结点处设置指向其父结点的指针,并设置左、右儿子标记。class QNode QNode*parent;/指向父结点的指针 bool LChild;/左儿子标记 Type weight;/结点所相应的载重量18将活节点加入到活节点队列中。4.EnQueue调用:EnQueue(Q,wt,i,n,bestw,E,bestE,bestx,true);196.3 装载问题5.优先队列式分支限界法解装载问题的优先队列式分支限界法用最大优先队列存储活结点表。活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。优先队列中优先级最大的活结点成为下一个扩展结点。以结点x为根的子树中全部结点相应的路径的载重量不超过它的优先级。子集树中叶结点所相应的载重量与其优先级相同。在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。此时可终止算法。206.4 布线问题1.算法思想解此问题的队列式分支限界法从起始位置a起先将它作为第一个扩展结点。与该扩展结点相邻并且可达的方格成为可行结点被加入到活结点队列中,并且将这些方格标记为1,即从起始方格a到这些方格的距离为1。接着,算法从活结点队列中取出队首结点作为下一个扩展结点,并将与当前扩展结点相邻且未标记过的方格标记为2,并存入活结点队列。这个过程一干脆着到算法搜寻到目标方格b或活结点队列为空时为止。即加入剪枝的广度优先搜寻。21移动方向设置226.4 布线问题Position offset4;offset0.row=0;offset0.col=1;/右 offset1.row=1;offset1.col=0;/下 offset2.row=0;offset2.col=-1;/左 offset3.row=-1;offset3.col=0;/上定定义移移动方向的方向的相相对位移位移 for(int i=0;i=m+1;i+)grid0i=gridn+1i=1;/顶部和底部 for(int i=0;i=n+1;i+)gridi0=gridim+1=1;/左翼和右翼设置置边界的界的围墙236.4 布线问题for(int i=0;i NumOfNbrs;i+)nbr.row=here.row+offseti.row;nbr.col=here.col+offseti.col;if(gridnbr.rownbr.col=0)/该方格未标记 gridnbr.rownbr.col =gridhere.rowhere.col+1;if(nbr.row=finish.row)&(nbr.col=finish.col)break;/完成布线 Q.Add(nbr);找到目标位置后,可以通过回溯方法找到这条最短路径。24v代码 bool FindPath(position,start,position finish,int&pathlen,position*path)256.5 0-1背包问题算法的思想 首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。优先队列分支限界法:优先先级已装袋的物品价已装袋的物品价值+剩下的最大剩下的最大单位重量价位重量价值的物品装的物品装满算法首先检查当前扩展结点的左儿子结点的可行性。假如该左儿子结点是可行结点,则将它加入到子集树和活结点优先队列中。当前扩展结点的右儿子结点确定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。当扩展到叶节点时为问题的最优值。266.5 0-1背包问题上界函数Bound:while(i=n&wi=cleft)/n表示物品总数,cleft为剩余空间 cleft-=wi;/wi表示i所占空间 b+=pi;/pi表示i的价值 i+;if(i=n)b+=pi/wi*cleft;/装填剩余容量装满背包return b;/b为上界函数276.5 0-1背包问题 while(i!=n+1)/非叶结点 /检查当前扩展结点的左儿子结点 Typew wt=cw+wi;if(wt bestp)bestp=cp+pi;AddLiveNode(up,cp+pi,cw+wi,true,i+1);up=Bound(i+1);/检查当前扩展结点的右儿子结点 if(up=bestp)/右子树可能含最优解 AddLiveNode(up,cp,cw,false,i+1);/取下一个扩展节点(略)分支限界搜分支限界搜寻过程程286.6 最大团问题给定无向图G=(V,E)。假如UV,且对随意u,vU有(u,v)E,则称U是G的完全子图。G的完全子图U是G的团当且仅当U不包含在G的更大的完全子图中。G的最大团是指G中所含顶点数最多的团。下图G中,子集1,2是G的大小为2的完全子图。这个完全子图不是团,因为它被G的更大的完全子图1,2,5包含。1,2,5是G的最大团。1,4,5和2,3,5也是G的最大团。1.问题描述296.6 最大团问题2.上界函数用变量cliqueSize表示与该结点相应的团的顶点数;level表示结点在子集空间树中所处的层次;优先先级:用cliqueSize+n-level+1 作为顶点数上界upperSize的值。在此优先队列式分支限界法中,upperSize事实上也是优先队列中元素的优先级。算法总是从活结点优先队列中抽取具有最大upperSize值的元素作为下一个扩展元素。306.6 最大团问题3.算法思想子集树的根结点是初始扩展结点,对于这个特殊的扩展结点,其cliqueSize的值为0。算法在扩展内部结点时,首先考察其儿子结点。在儿子结点处,将顶点i加入到当前团中,并检查该顶点与当前团中其它顶点之间是否有边相连。当顶点i与当前团中全部顶点之间都有边相连,则相应的左儿子结点是可行结点,将它加入到子集树中并插入活结点优先队列,否则就不是可行结点。316.6 最大团问题3.算法思想算法的while循环的终止条件是遇到子集树中的一个叶结点(即n+1层结点)成为当前扩展结点。对于子集树中的叶结点,有upperSizecliqueSize。此时活结点优先队列中剩余结点的upperSize值均不超过当前扩展结点的upperSize值,从而进一步搜寻不行能得到更大的团,此时算法已找到一个最优解。326.7 旅行售货员问题1.问题描述某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。他要选定一条从驻地动身,经过每个城市一次,最终回到驻地的路途,使总的路程(或总旅费)最小。路途是一个带权图。图中各边的费用(权)为正数。图的一条周游路途是包括V中的每个顶点在内的一条回路。周游路途的费用是这条路途上全部边的费用之和。旅行售货员问题的解空间可以组织成一棵树,从树的根结点到任一叶结点的路径定义了图的一条周游路途。旅行售货员问题要在图G中找出费用最小的周游路途。336.7 旅行售货员问题2.算法描述算法起先时创建一个最小堆,用于表示活结点优先队列。堆中每个结点的子树费用的下界lcost值是优先队列的优先级。接着算法计算出图中每个顶点的最小费用出边并用minout记录。假如所给的有向图中某个顶点没有出边,则该图不行能有回路,算法即告结束。假如每个顶点都有出边,则依据计算出的minout作算法初始化。算法的while循环体完成对排列树内部结点的扩展。对于当前扩展结点,算法分2种状况进行处理:346.7 旅行售货员问题2.算法描述1、首先考虑s=n-2的情形,此时当前扩展结点是排列树中某个叶结点的父结点。假如该叶结点相应一条可行回路且费用小于当前最小费用,则将该叶结点插入到优先队列中,否则舍去该叶结点。2、当sn-2时,算法依次产生当前扩展结点的全部儿子结点。由于当前扩展结点所相应的路径是x0:s,其可行儿子结点是从剩余顶点xs+1:n-1中选取的顶点xi,且(xs,xi)是所给有向图G中的一条边。对于当前扩展结点的每一个可行儿子结点,计算出其前缀(x0:s,xi)的费用cc和相应的下界lcost。当lcostbestc时,将这个可行儿子结点插入到活结点优先队列中。356.7 旅行售货员问题2.算法描述算法中while循环的终止条件是排列树的一个叶结点成为当前扩展结点。当s=n-1时,已找到的回路前缀是x0:n-1,它已包含图G的全部n个顶点。因此,当s=n-1时,相应的扩展结点表示一个叶结点。此时该叶结点所相应的回路的费用等于cc和lcost的值。剩余的活结点的lcost值不小于已找到的回路的费用。它们都不行能导致费用更小的回路。因此已找到的叶结点所相应的回路是一个最小费用旅行售货员回路,算法可以结束。算法结束时返回找到的最小费用,相应的最优解由数组v给出。3637386.8 电路板排列问题算法描述算法起先时,将排列树的根结点置为当前扩展结点。在do-while循环体内算法依次从活结点优先队列中取出具有最小cd值的结点作为当前扩展结点,并加以扩展。首先考虑s=n-1的情形,当前扩展结点是排列树中的一个叶结点的父结点。x表示相应于该叶结点的电路板排列。计算出与x相应的密度并在必要时更新当前最优值和相应的当前最优解。当sn-1时,算法依次产生当前扩展结点的全部儿子结点。对于当前扩展结点的每一个儿子结点node,计算出其相应的密度node.cd。当node.cdbestd时,将该儿子结点N插入到活结点优先队列中。396.8 电路板排列问题算法描述do/结点扩展 if(E.s=n-1)/仅一个儿子结点 int ld=0;/最终一块电路板的密度 for(int j=1;j=m;j+)ld+=BE.xnj;if(ld bestd)/密度更小的电路板排列 delete bestx;bestx=E.x;bestd=max(ld,E.cd);S=n-1的状况,的状况,计计算出算出此此时时的密度和的密度和bestd进进行比行比较较。406.8 电路板排列问题算法描述else /产生当前扩展结点的全部儿子结点 for(int i=E.s+1;i=n;i+)BoardNode N;N.now=new int m+1;for(int j=1;j=m;j+)/新插入的电路板 N.nowj=E.nowj+BE.xij;416.8 电路板排列问题int ld=0;/新插入电路板的密度 for(int j=1;j 0&totalj!=N.nowj)ld+;N.cd=max(ld,E.cd);if(N.cd bestd)/可能产生更好的叶结点 N.x=new int n+1;N.s=E.s+1;for(int j=1;j=r+1时依非减序排列,S1则取得微小值。同理假如选择Pk使t2pk依非减序排列,则S2取得微小值。这可以作为优先队列式分支限界法中的限界函数。456.9 批处理作业调度问题3.算法描述算法的while循环完成对排列树内部结点的有序扩展。在while循环体内算法依次从活结点优先队列中取出具有最小bb值(完成时间和下界)的结点作为当前扩展结点,并加以扩展。首先考虑E.s=n的情形,当前扩展结点E是排列树中的叶结点。E.sf2是相应于该叶结点的完成时间和。当E.sf2 bestc时更新当前最优值bestc和相应的当前最优解bestx。当E.sn时,算法依次产生当前扩展结点E的全部儿子结点。对于当前扩展结点的每一个儿子结点node,计算出其相应的完成时间和的下界bb。当bbbestc时,将该儿子结点插入到活结点优先队列中。而当bbbestc时,可将结点node舍去。466.9 批处理作业调度问题 while(E.s=n)if(E.s=n)/叶结点 if(E.sf2 bestc)bestc=E.sf2;for(int i=0;i n;i+)bestxi=E.xi;delete E.x;3.算法描述 当当E.sf2bestc时,更,更新当前最新当前最优值bestc和相和相应的最的最优解解bestx476.9 批处理作业调度问题3.算法描述else/产生当前扩展结点的儿子结点 for(int i=E.s;i n;i+)Swap(E.xE.s,E.xi);int f1,f2;int bb=Bound(E,f1,f2,y);if(bb bestc)MinHeapNode N;N.NewNode(E,f1,f2,bb,n);H.Insert(N);Swap(E.xE.s,E.xi);delete E.x;/完成结点扩展当当bbbestc时,将儿,将儿子子结点插入到活点插入到活结点点优先先队列中列中