同步至我的阿里云博客(https://yq.aliyun.com/users/1320894660843258)
分层规划的旅行商问题解决方案
/上周在无意间跟室友讨论到TSP问题时,我觉得应该把这个问题整合一下,并给出自己的解决方案,同时代码公布在github,有人做成其他版本的与其他人探讨共同进步。
无特别说明情况下,聚类指的是kmeans聚类/
摘要
本文采用分层规划的思想,层层聚类,直至最底层单个城市群数量满足一定阈值,然后利用整数规划求最底层城市群的精确解,单层之间的城市群路径规划同样采用整数规划求精确解,这里的城市群路径规划指的是城市群的聚类中心之间的路径规划,最高层为闭合路径的TSP问题,以下单层包括底层都为确定起点终点的不闭合TSP问题,这里的不闭合TSP问题的起点终点贪心的由上一级城市群聚类中心求出的路径来确定哪两个城市群相邻,并由此计算此相邻城市群的最近子城市群对。
求出近似路径后再进行局部的随机优化。
/简单的讲,类比在全球寻找一条可以走遍所有城市的最短路,每个城市只能访问一次,我们先找大范围的路径,如亚洲->非洲->欧洲->北美洲->南美洲->大洋洲->亚洲,然后在往下分层,比如非洲,先计算非洲与它的前驱亚洲后继欧洲之间最近的国家对,比如是埃及-伊朗,利比亚-意大利,这样确定了进入非洲的起点埃及,终点利比亚,在非洲国家之间解决走完所有国家且仅访问一次的路径,再针对其中某个国家进行分析,直至到底层的城市为止。最后路径规划出来后再对求出的路径进行局部的优化,特别需要关注的是包含起点终点部分的路径。/
综述
对于大规模TSP问题,尚没有太好的有效解决方案,现在智能算法如蚁群算法,遗传算法,人工神经网络更为流行与实用。这些在其他文章中可以找到相应的内容。遗传算法(GA)寻解空间好大,我超喜欢GA的。
问题建模
TSP问题的描述
给定城市与城市间的连接关系,在有解的前提下,从起点出发,寻找一条路径回到起点,这条路径需要满足经过所有城市,并且每个城市仅能经过一次。
即
本文提出的解决方案的建模与数学描述
-
首先利用分层规划,层层聚类,直至最底层单个城市群数量满足一定阈值,然后利用整数规划求最底层城市群的精确解。
-
最高层为闭合路径的TSP问题,以下单层包括底层都为确定起点终点的不闭合TSP问题,这里的不闭合TSP问题的起点终点贪心的由上一级城市群聚类中心求出的路径来确定哪两个城市群相邻,并由此计算此相邻城市群的最近子城市群对。
-
单层之间的城市群路径规划同样采用整数规划求精确解,这里的城市群路径规划指的是城市群的聚类中心之间的路径规划。
对于Top层如下图所示求闭合路径
Top示意.png
对于非top层,实则为确定起点终点的聚类中心之间的路径规划,如下图。
子城市群示意.png 子城市顺延示意.png
对于子层,如果满足子层节点中城市数量不超过一定阈值(整数规划求精确解时间允许的城市数量),则不进行分裂,直接将其进入下一层。
寻路示意.png
本文的模型总结与分析
模型算法
整体结构类似于树的广搜,先处理顶层,再处理后续子层。采取一个队列存储当前层的城市信息。分支定界也让计算复杂度得以控制。
整数规划求解小规模TSP问题算法
推荐这篇文章Optimization by Integer Programming
确定起点终点的不闭合TSP模型解决算法
这个地方很诡异,建立转化为闭合路径的TSP问题来计算,比如我们可以增加了这样一条规则:
virtual_node = rand();//设定一个虚拟节点,随机生成坐标
virtual_node->start_node = 0;//虚拟节点到起始点的距离为0
virtual_node->end_node = 0;//虚拟节点到终止点的距离为0
virtual_node->other_nodes = INF;//虚拟节点到除了起点终点的其他节点的距离为很大一个数值
注意,这个是在计算出距离之上直接修改,这个设定在实际上肯定不存在,因为这样会导致起点终点直联的距离不等于由经过虚拟节点的距离,不过这并不影响计算。
有了这个设定,在这样的一个闭合TSP问题中,肯定会包含一条start_node-virtual_node-end_node的路径,去掉虚拟节点以及其两边,则为确定起点终点的路径,而且因为虚拟节点到起点终点的距离均为0,计算时候也不影响优化结果,解仍然是最优的。
城市群内部子城市群路径起点终点的确定算法
因为聚类中心数量并不大,而且可控,直接暴搜走起。
整体算法流程
logicImp()
%初始化一些数据
city;MaxCityNum;...
%分层处理
while(true)
%如果全部满足底层条件,退出死循环
if allCityGroupMinEnough(cityCell,MaxCityNum)
break;
end
%否则处理单层问题
todo
for i=1:cityCellLength
%子城市群预处理
todo
%如果子城市群满足不分裂条件,该子城市群出队再入队,跳过当前子城市群
if cur_city_group_x < MaxCityNum
todo
continue;
end
%子城市群边界的处理
todo
%聚类得到类中心坐标向量与分组
todo
%得到起始点与终止点
todo
%如果起点终点一样,即产生冲突,改变一个
todo
%规划路径,分为顶层与非顶层
if topFlag == 1
circleTspSolver();
topFlag = 0;
else
tspSolver();
end
%检索排序子城市群,分裂的子节点入队。
todo
end
cityCell = cityCellNew;
end
%处理最底层
for i =1:cityCellLength
%城市群预处理
todo
%底层最近邻的起点终点
todo
%如果起点终点一样,即产生冲突,改变一个
todo
% 调用整数规划
tspSolver();
%处理结果
todo
end
end
实验
在tsplib数据集上的测试(我们只测试个大规模的),与精确解稳定在10%的损失,不逊于一般论文的方法的测试结果!
数据集名字1 | 最优解 | 本文得到的解 | 比例 |
---|---|---|---|
ja9847 | 491924 | 561460 | 0.8762 |
网友评论