本文共 1853 字,大约阅读时间需要 6 分钟。
在当前节点(扩展节点)处,先生成其所有的儿子节点(分支),然后再从当前的活节点(当前节点的子节点)表中选择下一个扩展节点。为了有效地选择下一个扩展节点,加速搜索的进程,在每一个活节点处,计算一个函数值(限界),并根据函数值,从当前活节点表中选择一个最有利的节点作为扩展节点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解。分支限界法解决了大量离散最优化的问题。
1.队列式(FIFO)分支限界法
队列式分支限界法将活节点表组织成一个队列,并将队列的先进先出原则选取下一个节点为当前扩展节点。
2.优先队列式分支限界法
优先队列式分支限界法将活节点表组织成一个优先队列,并将优先队列中规定的节点优先级选取优先级最高的下一个节点成为当前扩展节点。如果选择这种选择方式,往往将数据排成最大堆或者最小堆来实现。
有一批共n个集装箱要装上2艘载重量分别为c1,c2的轮船,其中集装箱i的重量为wi,且要求确定是否有一个合理的装载方案可将这n个集装箱装上这2艘轮船。
可证明,采用如下策略可以得到一个最优装载方案:先尽可能的将第一艘船装满,其次将剩余的集装箱装到第二艘船上。代码如下:
//分支限界法解装载问题//子函数,将当前活节点加入队列templatevoid EnQueue(Queue &Q, Type wt, Type &bestw, int i, int n) { if(i == n) //可行叶结点 { if(wt>bestw) bestw = wt ; } else Q.Add(wt) ; //非叶结点}//装载问题先尽量将第一艘船装满//队列式分支限界法,返回最优载重量template Type MaxLoading(Type w[],Type c,int n){ //初始化数据 Queue Q; //保存活节点的队列 Q.Add(-1); //-1的标志是标识分层 int i=1; //i表示当前扩展节点所在的层数 Type Ew=0; //Ew表示当前扩展节点的重量 Type bestw=0; //bestw表示当前最优载重量 //搜索子集空间树 while(true) { if(Ew+w[i]<=c) //检查左儿子 EnQueue(Q,Ew+w[i],bestw,i,n); //将左儿子添加到队列 //将右儿子添加到队列 即表示不将当前货物装载在第一艘船 EnQueue(Q,Ew,bestw,i,n); Q.Delete(Ew); //取下一个节点为扩展节点并将重量保存在Ew if(Ew==-1) //检查是否到了同层结束 { if(Q.IsEmpty()) return bestw; //遍历完毕,返回最优值 Q.Add(-1); //添加分层标志 Q.Delete(Ew); //删除分层标志,进入下一层 i++; } }}
算法MaxLoading的计算时间和空间复杂度为O(2^n).
上述算法可以改进,设r为剩余集装箱的重量,当Ew+r<=bestw的时候,可以将右子树剪去。因为最优值不可能出现在下面了。
改进代码如下:
分支限界法解决了大量离散最优化问题。
参考资料计算机算法设计与分析/王晓东编著。-3版。-北京:电子工业出版社,2007.5
转载地址:http://dhsel.baihongyu.com/