目录
1.题目分析
2.解题思路
3.C++源代码(部分)
4.结论
1.题目分析
旅行商问题内容:一个售货员必须访问n个城市,恰好访问每个城市一次,并最终回到出发城市,且整个旅行费用最低。
分析:这个问题的实质就是在一个带权的完全无向图当中寻找一个总权值最小的回路, 它是一个NP完全问题。对于NP完全问题,我们可以采取动态规划法或者分支限界法求解,很多情况下,这两种方式比穷举搜索法有效得多。
![](https://img-blog.csdnimg.cn/img_convert/152ed3e1d0166cdcc5fdb837d14fcb07.jpeg)
4顶点无向带权图
![](https://img-blog.csdnimg.cn/img_convert/09a7921ec1b0b410dda34e3e25a84df5.jpeg)
n=4时旅行商问题的解空间树
2.解题思路
旅行商问题的解空间树是一棵排列树。分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。采取分支限界法的原因是在寻找到一个最优解之后,如果在接下来的某个过程当中所得到的权值已经超过最优解,那么我们就可以将这个节点及之后的节点舍弃,转而去遍历新的一个可能。在获得新的最优解之后再去替换之前的最优解,然后重复循环以上过程。我们就可以以一个比较高的效率去遍历出旅行商问题的最优解。
优先队列式的分支界限法将活结点表组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。对排列树的优先队列式分支界限法有两种不同的实现方式。我们采用的是其中一种,仅使用优先队列来存储活结点。优先队列中的每个活结点都存储从根到该活结点的相应路径。
3.C++源代码(部分)
实现子树存在最优解时,将结点插入最小堆,源代码如下:
{//子树可能含最优解,结点插入最小堆
MinHeapNode * N;
N = (MinHeapNode*)malloc(sizeof(MinHeapNode));
N->x = new int[n];
for(int j = 0; j < n; j++)
N->x[j] = E->x[j];
N->x[E->s + 1] = E->x[i];
N->x[i] = E->x[E->s + 1];/*添加当前路径*/
N->cc = cc; /*更新当前路径距离*/
N->s = E->s + 1; /*更新当前节点*/
N->lcost = b; /*更新当前下界*/
N->rcost = rcost;
N->next = NULL;
Insert(N); /*将这个可行儿子结点插入到活结点优先队列中*/
}
判断该叶结点相应一条可行回路,且最短路径小于当前最短路径,源代码如下:
if(a[E->x[n - 2]][E->x[n - 1]] != NoEdge && /*当前要扩展和叶节点有边存在*/
a[E->x[n - 1]][1] != NoEdge && /*当前叶节点有回路*/
(E->cc + a[E->x[n - 2]][E->x[n - 1]] + a[E->x[n - 1]][1] < bestc /*该节点相应路径小于最小路径*/
|| bestc == NoEdge))
4.结论
分支限界法,首先确认上下界,根据界限函数估计结点的目标函数的可能取值,设计出界限函数,进行广度优先搜索,并对根节点到该节点路径大小进行保存,求得最优解后不断回溯,确定最优解的各个分量。采用活结点将所有的可行子节点进行拓展,并估算最后的可能值,如果比最优解大,就舍弃,重新规划路线。否则,更新为最优解。这种方法能够简化计算量,提高效率。