VNS求解TSP问题(berlin52为例)
运行演示
源码
基于参考【1】的源码,进行了修改,加速迭代。附部分源码:
//邻域结构1 使用two_opt_swap算子 随机选择两点,区间反转。
void neighborhood_one(SOLUTION & solution, CITIES *cities)
{
int i, k, count = 0;
int max_no_improve = 60;//迭代60次无相对优化,就认为是最优解。7526最优解。如果不是这个解,可以增大该值。
int inital_cost = solution.cost; //初始成本
int now_cost = 0;
int cur_delta = 0; //cxy新增
//SOLUTION current_solution = solution;
//两两节点区间反转,初次计算成本相对初始成本的增量。
for (int i = 0; i < CITY_SIZE - 1; i++)
{
for (k = i + 1; k < CITY_SIZE; k++)
{
Delta1[i][k] = calc_delta1(i, k, solution.permutation, cities);
}
}
//循环中会在选择了区间反转后重新进行成本增量矩阵的计算。
do
{
count++;
for (i = 0; i < CITY_SIZE - 1; i++)
{
for (k = i + 1; k < CITY_SIZE; k++)
{
if (Delta1[i][k] < cur_delta)//cur_delta //对于相对成本增量为负值的,更新当前解。如果邻域中有很多增量成本为负值,相当于只 邻域里为负值成本的最后一个有效
{
//current_solution = solution;
two_opt_swap(solution.permutation, i, k); //反转当前解的 i k节点之间的区间
now_cost = inital_cost + Delta1[i][k];//新的成本
solution.cost = now_cost;//更新解的成本。覆盖了
inital_cost = solution.cost;//
cur_delta = Delta1[i][k];
Update1(i, k, solution.permutation, cities, Delta1);//重新计算区间反转后的解的 变邻域成本增量
count = 0; //count复位,再次从头开始寻找
}
}
}
}while (count <= max_no_improve);
}
//邻域结构2 使用two_h_opt_swap算子。随机选两个节点插入最前。插入操作。
void neighborhood_two(SOLUTION & solution, CITIES *cities)
{
int i, k, count = 0;
int max_no_improve = 60;//最大无优化次数 ,终止条件
int inital_cost = solution.cost; //初始成本
int now_cost = 0;
int delta = 0;
int cur_delta = 0;//cxy 新增
do
{
count++;
for (i = 0; i < CITY_SIZE - 1; i++)//遍历所有城市
{
for (k = i + 1; k < CITY_SIZE; k++)//遍历当前城市后面的
{
delta = calc_delta2(i, k, solution.permutation, cities);//随机产生两点,塞进新排列头部。其余的按顺序往后逐个塞进去。计算新的顺序 成本改变量
if (delta < cur_delta)//cur_delta
{
//cout<<"delta = " <<delta<<endl;
two_h_opt_swap(solution.permutation, i, k);//随机产生两点,塞进新排列头部。其余的按顺序往后逐个塞进去
now_cost = inital_cost + delta;
solution.cost = now_cost;
inital_cost = solution.cost;
cur_delta = delta;
count = 0; //count复位
}
}
}
} while (count <= max_no_improve);
}
//VND
//best_solution最优解
//current_solution当前解
void variable_neighborhood_descent(SOLUTION & solution, CITIES * cities)
{
SOLUTION current_solution = solution;//局部当前解=全局解
int l = 1;
cout <<"=====================VariableNeighborhoodDescent=====================" << endl;
while(true)
{
switch (l)
{
case 1://邻域1 搜索
neighborhood_one(current_solution, cities);
cout << setw(45) << setiosflags(ios::left) <<"Now in neighborhood_one , current_solution = " << current_solution.cost << setw(10) << setiosflags(ios::left) << " solution = " << solution.cost << endl;
if (current_solution.cost < solution.cost)
{
solution = current_solution;//更新全局解
l = 0;//下一轮搜索
}
break;
case 2://邻域2 搜索
neighborhood_two(current_solution, cities);
cout << setw(45) << setiosflags(ios::left) << "Now in neighborhood_two , current_solution = " << current_solution.cost << setw(10) << setiosflags(ios::left) << " solution = " << solution.cost << endl;
if (current_solution.cost < solution.cost)
{
solution = current_solution;//更新全局解
l = 0;//下一轮搜索
}
break;
default:
return;
}
l++;
}
}
//此源码有问题,修改后可以找到7526
int main()
{
srand((unsigned) time(0));
SOLUTION best_solution;//最优解 排序
random_permutation(best_solution.permutation);//生成随机初始最优排序
best_solution.cost = cost_total(best_solution.permutation, berlin52);//初始成本,初始总路线长度
cout << "初始总路线长度 = " << best_solution.cost << endl;
variable_neighborhood_search(best_solution, berlin52);//执行变邻域搜索
cout << endl << endl << "搜索完成!最优路线总长度 = " << best_solution.cost << endl;
cout << "最优访问城市序列如下:" << endl;
for (int i = 0; i < CITY_SIZE; i++)
{//宽度4,左对齐,最优解顺序
cout << setw(4) << setiosflags(ios::left) << best_solution.permutation[i];
}
cout << endl << endl;
return 0;
}
参考
https://github.com/accelerate0818/VariableNeighborhoodSearchTSP
https://github.com/B06SuperLab/TSP_GA
https://www.cnblogs.com/dengfaheng/p/10852917.html
https://cloud.tencent.com/developer/article/1548088