算法分析 | 分支限界法 | (优先队列)优化后的旅行商问题
顺便复习了类的继承,派生类的写法如下:
Derive (int _cl, int _rl, int _zl, int _id):Base(_cl, _id),rl(_rl),zl(_zl){}
注意,
1.基类的构造函数Base() 的两个参数是实参,Derive的形参传递给Base(),就是实参.如果写成Base(3,5),也不出错.
2.基类构造函数的调用放在函数头部,不能放在函数体{}中。
一.问题描述
优先队列中,zl=cl+rl作为优先级
cl:当前走过的路程.
rl:剩余的路径长度 拥剩余每个结点的最小出边之和. 例如有一表示1,2,3,4 四个城市的矩阵:
{INF,15,30,5}, min=5
{15,INF,6,12}, min=6
{30,6,INF,3}, min=3
{5,12,3,INF } min=3
初始时,剩余4个城市 rl=5+6+3+3=17 (注意,不同结点的最小出度可能相同)
二.代码实现
1.全局变量区,有一部分继承自TCP.h,(详见文章上一篇)
#include"TSP.h" //继承全局变量和结构体State2
int minsum; //记录剩余节点的最小出路之和
int minout[N3]; //记录各个结点的最小出路
//记录状态
struct State3: public State2
{
int rl;
int zl;
State3() {};
State3(int _cl, int _rl, int _zl, int _id):State2(_cl, _id),rl(_rl),zl(_zl){}
//zl越小的,优先级越大
friend bool operator<(const State3& a, const State3& b)
{
return a.zl > b.zl;
}
};
2.Bound()下界函数,作用有二:
(1)当某个结点和其它所有结点都不连通时,判定为false
(2)记录各结点的最小出度 和 所有结点的最小出度之和.记录在minout[] 和minsum.
问题在于,优先级zl = cl + rl. cl 还好理解, rl 的初始值=minsum; 每拓展出一个结点,rl -= minout[ i ]
另外,活结点的约束条件是 if(zl<bestp)
最小出度之和为什么能决定优先级和限界条件?
网上找不到对这个下界函数的解释.如果你有想法请评论.
bool Bound() {
for (size_t i = 0; i <N3; i++)
{
int minl = INF;
for (size_t j = 0; j < N3; j++)
{
if (T3[i][j] != INF && T3[i][j] < minl)
{
minl = T3[i][j];
}
}
if (minl==INF)//未找到联通路径
{
return false;
}
minout[i] = minl;
minsum += minout[i];
}
return true;
}
3.遍历函数
第一次运行时忘了加pop()弹出队首元素
double TravelingBFS_2()
{
if (!Bound())
{
cout << "无可行解" << endl;
return -1;
}
//循环前的初始化准备
State3 livenode, newnode;
newnode = State3(0, minsum, minsum, 1); //minsum已在之前调用的Bound()中算出
for (size_t i = 0; i < N3; i++)
newnode.x[i] = i;
priority_queue<State3> q;
q.push(newnode);
//开始循环
while (!q.empty())
{
livenode = q.top();
q.pop();
int t = livenode.id;
//活结点的终止循环(约束)条件
if (t == N3 - 1) //到达倒数第二个结点
{
if (T3[livenode.x[0]][livenode.x[N3 - 1]] != INF && //最后一个城市和起点城市有连接
T3[livenode.x[N3 - 1]][livenode.x[N3 - 2]] != INF && //倒数第二个城市和最后一个城市有连接
livenode.cl + T3[livenode.x[N3 - 2]][livenode.x[N3 - 1]] + T3[livenode.x[0]][livenode.x[N3 - 1]] < bestp3
//相加后 < 目前最优值
)
{
bestp3 = livenode.cl + T3[livenode.x[N3 - 2]][livenode.x[N3 - 1]] + T3[livenode.x[0]][livenode.x[N3 - 1]];//更新
bestx3 = livenode.x;
}
continue; //到达倒二结点已经求出一个bestx[],或已知不存在最佳顺序,必须跳出本次循环
}
//活结点的限界条件
if (livenode.cl >= bestp3)
continue;
//开始遍历分支结点
for (size_t i = t; i < N3; i++)
{
if (T3[livenode.x[t-1]][livenode.x[i]]!=INF)//约束条件:当前结点和下一个待测节点有链接
{
int cl = livenode.cl + T3[livenode.x[t - 1]][livenode.x[i]];
int rl = livenode.rl - minout[livenode.x[i]];
int zl = cl + rl;
if (zl < bestp3)
{
newnode = State3(cl, rl, zl, t + 1);
newnode.x = livenode.x;
swap(newnode.x[t], newnode.x[i]);//t来自livenode.id,是livenode状态要处理的下一个结点序号,显然要换成i
q.push(newnode);
}
}
}
}
return bestp3;
}
4.初始化&调用函数
void TSP_2() {
//初始化
bestp3 = INF;
bestx3.resize(N3, 0);
minsum = 0;
//遍历
cout << "最短距离为: " << TravelingBFS_2();
cout << endl;
cout << "最优旅行顺序: ";
for (int i = 0; i < N3; i++)
{
cout << bestx3[i] << "-";
}cout << "0";
}
三.Bug分析
1.在源.cpp调用TSP_2(),什么显示都没有,连距离为 "字样都没打印出来.

而且无法选择其它选项,说明程序陷入死循环,无法结束运行 <- 优先队列一直不为空 <- 忘记加pop()出队已有的元素.

浙公网安备 33010602011771号