分支限界算法策略
分支限界法常以广度优先的方式搜索问题的解空间树。 在分支限界法中,每一个活结点只有一次机会成为扩展结点。 活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。 此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。
分支节点的选择-常见的两种分支限界法 从活结点表中选择下一扩展结点的不同方式导致不同的分支限界法: 队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。 优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。 最大优先队列:使用最大堆,体现最大效益优先 最小优先队列:使用最小堆,体现最小费用优先
提高分支限界算法的效率 实现分支限界算法时,首先确定目标值的上/下界(求最大值时,定义上界函数;求最小值时,定义下界函数),边搜索边剪掉搜索树的某些分支,提高搜索效率。 在搜索时,绝大部分需要用到剪枝。“剪枝”是搜索算法中优化程序的一种基本方法,需要通过设计出合理的判断方法,以决定某一分支的取舍。 若我们把搜索的过程看成是对一棵树的遍历,那么剪枝就是将树中的一些“死结点”,不能到达最优解的枝条“剪”掉,以减少搜索的时间。
限界函数 利用约束函数和限界函数剪去无效的分支,提高搜索效率。 求解最大值问题时: 维护一个活节点表,从活结点表中选择一个结对作为扩展节点 对扩展节点的每个分支,计算器上界值Bound(i). 如果当前最大目标函数值bestc>=Bound(i),那么结点 i 就不会放入活结点表中个,否则放入。从而完成剪枝操作。
2、数据结构 设queue——队列,存储从(1,1)可达的点(queue[k][1…2])以及到达该点所需要的最少步数(queue[k][3])(0≤k≤192+1)。队列的首指针为head,尾指针为tail。初始时,queue中只有一个元素为(1,1),最少步数为0。 S[][] —记录(1,1)到每点所需要的最少步数。显然,问题的答案是s[x1][y1]和s[x2][y2]。初始时,s[1][1]为0,除此之外的所有元素值设为-1。 3、约束条件 ⑴不能越出界外。由于马的所有可能的落脚点s均在s的范围内,因此一旦马越出界外,就将其s值赋为0,表示“已经扩展过,且(1,1)到达其最少需要0步”。这看上去是荒谬的,但可以简单而有效地避免马再次落入这些界外点。 ⑵该点在以前的扩展中没有到达过。如果曾经到达过,则根据广度优先搜索的原理,先前到达该点所需的步数一定小于当前步数,因此完全没有必要再扩展下去。 由此得出,马的跳后位置(x,y)是否可以入队的约束条件是s[x][y]<0。
单源最短路径问题 给定带权有向图G=(V,E),其中每条边的权是非负实数。给定V中的一个顶点,称为源。 现在要计算从源到所有其它各顶点的最短路长度,这里路的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。 每条边上标注有字母和数字,在字母旁边的数字为路长。
#include <iostream> #include <string> #include <queue> using namespace std; class Graphic{ int n;//图中顶点的个数 int e;//边的数目 int **adjmatrix;//邻接矩阵,存储图 int *dist;//dist[n],存储单元点到其他n-1个顶点的最短路的长度 int *prev;//prev[i]=j 存储顶点i 的前驱结点为j , 利用这些前驱结点可以找到源点到顶点i的最短路 int start;//源点 public: Graphic(int n, int e); void ShortPath(); void display(); };旅行商问题(TSP问题) 是指一销售商从n个城市中的某一城市出发,不重复地走完其余n—1个城市并回到原出发点,在所有可能的路径中求出路径长度最短的一条。本题假定该旅行商从第1个城市出发。 输入 对每个测试例,第1行有两个整数:n(4≤n≤10)和m(4≤m≤20 ) ,n是结点数,m是边数。接下来m行,描述边的关系,每行3个整数:(i,j),length,表示结点i到结点j的长度是length。 当n=0时,表示输入结束。 输出 对每个测试例,输出最短路径长度所经历的结点,最短的长度。