贪心算法求解 TSP 旅行商问题及其实现
文章目录
- 一、TSP 概述
- 1. TSP
- 2. 数学模型
- 3. TSP分类
- 二、贪心算法
- 1. 算法思路
- 2. 算法框架
- 3. 问题
- 三、贪心算法求解 TSP
一、TSP 概述
1. TSP
旅行商问题即 TSP(Traveling Salesman Problem),又称为货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
TSP问题是一个组合优化问题,该问题可以被证明具有NPC计算复杂性。从图论的角度来看,该问题实质是给定一个带权完全无向图(顶点表示城市,边表示道路,权重是道路的成本或距离),找一个权值最小的 Hamilton 回路。
2. 数学模型
记 G = (V, E) 为赋权图,V = {1, 2 , ……,n} 为顶点集,E 为边集,各顶点间距离为 Cij,已知(Cij > 0,Cij = +∞,i,j ∈ V),并设
xij={1,边(i,j)在最优路线上0,其他x~ij~= \begin{cases} 1,边(i, j)在最优路线上 \\ 0,其他 \end{cases}x ij ={1,边(i,j)在最优路线上0,其他
则旅行商问题的数学模型可写成如下的线性规划形式:
p=∑i≠jcijxijp = \sum_{i ≠ j} c_{ij}x_{ij}p=i=j∑cijxij
s.t.={∑j≠icij=1,i∈V∑i≠jcij=1,j∈V∑i,j∈Sxij≤∣K∣−1,K⊂Vxij∈{0,1}i,j∈Vs.t.=\begin{cases} \sum_{j ≠ i} c_{ij} = 1 ,& i∈V \\ \sum_{i ≠ j} c_{ij} = 1 ,& j∈V \\ \sum_{i,j∈S} x_{ij} ≤|K|-1 ,& K ⊂V \\ x_{ij}∈\{0, 1\} & i,j∈V\\ \end{cases}s.t.=⎩⎪⎪⎪⎨⎪⎪⎪⎧∑j=icij=1,∑i=jcij=1,∑i,j∈Sxij≤∣K∣−1,xij∈{0,1}i∈Vj∈VK⊂Vi,j∈V
K 为 V 的所有非空子集,|K| 为集合 K 中所含图 G 的顶点个数。前两个余数意味着对每个顶点而言,出度和入度都为1,后一约束则保证没有任何子回路解的产生,于是满足上述约束的解构成了一条 Hamilton 回路。
3. TSP分类
旅行商问题按把不同的分类方法可以分为不同的种类,这里只介绍距离矩阵划分: 当 cij = cji,(i, j ∈ V)时,问题被称为对称型旅行商问题,反之称为非对称型旅行商问题,非对称旅行商问题可以化为对称型旅行商问题,用对称型的方法求解。当对所有的 i, j, k ∈[1, n],有不等式 cij + cjk ≥ cik,问题满足三角形不等式的,也称三角型旅行商问题。
旅行售货商问题(TSP)是组合优化领域的经典问题之一,而其中考虑多个旅行商的多旅行商问题(MTSP)是经典的旅行商问题的扩展,多种扩展形式1如下:
- 最小哈密顿链的问题:起点和终点不同;
- 非对称旅行商问题(asymmetric TSP):距离矩阵非对称的旅行商问题;
- 多人旅行商问题(muti-person TSP):由多人完成旅行的旅行商问题;
- 多目标旅行商问题(multi-objective TSP);
- 依次排序问题(Sequence ordering problem ,SOP):这类问题是非对称旅行商问题,在给定一系列顶点和距离矩阵下,寻找最短从顶点 1 到顶点 n 哈密顿链,同时满足限制:某些顶点要在一些顶点之前被连接。
- 载货量受限制的车辆路径问题(Capacitated vehicle routing problem,CVRP):给定 n-1 个顶点和一个仓库,一直顶点和顶点、仓库和顶点的距离,卡车载货量受限制,卡车每次在部分顶点和仓库之间往返,寻求一条经过所有顶点的最短路线。
二、贪心算法
贪心算法,又名贪婪算法,是一种常用的求解最优化问题的简单、迅速的算法。贪心算法总是做出在当前看来最好的选择,它所做的每一个在当前状态下某种意义上是最好的选择即贪心选择,并希望通过每次所作的贪心选择导致最终得到问题最优解。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
1. 算法思路
贪心算法以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解。虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不要回溯。
贪心算法求解具有以下性质2:
- 贪心选择性质:一个问题的整体最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。这就是贪心选择性质。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解
- 最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心法求解的关键所在。
2. 算法框架
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择,而贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
//问题随机初始解
while(能向总目标前进一步)
{//利用可行的决策,从候选集合中求出可行解的一个解元素;
}
3. 问题
贪心算法也存在如下问题3:
- 不能保证求得的最后解是最佳的;
- 不能用来求最大最小解问题;
- 只能在某些特定条件约束的情况下使用,例如贪心策略必须具备无后效性等。
三、贪心算法求解 TSP
贪心策略基本思路:从一节点出发遍历所有能到达的下一节点,选择距离最近的节点作为下一节点,然后把当前节点标记已走过,下一节点作为当前节点,重复贪心策略,以此类推直至所有节点都标记为已走节点结束。
TSP 数据集来自于 TSPLIB 上的 att48.tsp,这是一个对称 TSP 问题,城市规模为48,其最优值为10628。其距离计算方法如下:
The edge weight type ATT corresponds to a special “pseudo-Euclidean” distance function. Let x[ i ] and y[ i ] be the coordinates of node i. The distance between two points i and j is computed as follows:
double dis = sqrt((pow((double)x[i] - x[j], 2) / 10 + pow((double)y[i] - y[j], 2) / 10 ));
int disInt = (int)dis;
if(disInt < dis) dis = disInt + 1;
else dis = disInt;
具体代码如下:
/********************************************************************************************************************** TSP 算例来自TSPLIB,att48.tsp 数据集,其中有 48 个城市,距离为伪欧式距离* TSPLIB is a library of sample instances for the TSP (and related problems)from various sources and of various types.* 目前最佳解总距离为 10628,其中距离的计算方式为 sqrt((x*x + y*y)/10)* 使用贪心策略求解,解集总距离为 12861,可见贪心策略只是局部最优解
**********************************************************************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>// 城市数量 N
#define N 48
// 城市距离矩阵
int distance[N][N];/************************************************************************ Function :init()* Description:从文件中读取城市坐标,并计算城市之间的距离 distance[N][N] * Input :void* Output :void* Return :void***********************************************************************/
void init()
{//城市的 x 和 y 坐标int x[N] = { 0 };int y[N] = { 0 };//从 data.txt 文件读取数据FILE* fp;if ((fp = fopen("..//att48.txt", "r")) == NULL)//if ((fp = fopen("..//kroB100.txt", "r")) == NULL){printf("can not open the file!");exit(0);}while (!feof(fp)){int count;fscanf(fp, "%d", &count);fscanf(fp, "%d%d", &x[count - 1], &y[count - 1]);}fclose(fp);//计算城市之间距离for (int i = 0; i < N - 1; i++){distance[i][i] = 0; // 对角线为0for (int j = i + 1; j < N; j++){double dis = sqrt((pow((double)x[i] - x[j], 2) / 10 + pow((double)y[i] - y[j], 2) / 10));int disInt = (int)dis;distance[i][j] = dis == disInt ? disInt : disInt + 1;distance[j][i] = distance[i][j];}}distance[N - 1][N - 1] = 0;
}/************************************************************************ Function :TSPGreedyAlgorithm()* Description:贪心策略求解 TSP 问题* Input :void* Output :TSP 路径和对应的总距离* Return :void***********************************************************************/
void TSPGreedyAlgorithm()
{//总路程int totalDistance = 0; //默认从 0 开始遍历int current = 0; //标识城市是否被访问,访问过置为 1bool visit[N] = { false };visit[0] = 1;printf("TSP 路径为:%d ->", 1);//遍历 N - 1 次for (int i = 1; i < N; i++){//设置较大的距离初始值用来选取最近邻int min_distance = 0x7fffffff;//保存当前最近邻城市int temp;//循环选取城市for (int j = 1; j < N; j++){if (!visit[j] && distance[current][j] < min_distance){min_distance = distance[current][j];temp = j;}}visit[temp] = 1;current = temp;totalDistance += min_distance;printf(" %d ->", temp + 1);}totalDistance += distance[current][0];printf(" %d\n", 1);printf("TSP 总距离为:%d\n", totalDistance);
}int main()
{init();TSPGreedyAlgorithm();return 0;
}
结果如下:
可见,贪心算法求解 TSP 问题只能得到局部最优解,如果需要得到最优解,需要采用局部搜索算法等非精确性算法,作者将在后文中继续介绍其他方法求解 TSP 问题。
The multiple traveling salesman problem: an overview of formulations and solution procedures. ↩︎
计算机算法设计与分析研究,新华出版社,2015.09. ↩︎
计算机算法基础,西南交通大学出版社,2015.02. ↩︎
贪心算法求解 TSP 旅行商问题及其实现相关推荐
- 基于贪心算法求解TSP问题(JAVA)
前段时间在搞贪心算法,为了举例,故拿TSP来开刀,写了段求解算法代码以便有需之人,注意代码考虑可读性从最容易理解角度写,没有优化,有需要可以自行优化! 详细 代码下载:http://www.demod ...
- 人工蜂群算法求解TSP旅行商问题C++(2020.11.13)
ABC算法求解TSP问题的C++实现 1.输入数据文件:bayg29.tsp 2.头文件 3.所需的类 3.1 城市类City 3.2 包含城市的地图类Graph 3.3 蜜蜂类Bee 3.4 人工蜂 ...
- tsp java_基于贪心算法求解TSP问题(JAVA)
前段时间在搞贪心算法,为了举例,故拿TSP来开刀,写了段求解算法代码以便有需之人,注意代码考虑可读性从最容易理解角度写,没有优化,有需要可以自行优化! 一.TPS问题 TSP问题(Travelling ...
- 贪心算法求解TSP问题(python)
这里使用贪心算法求解TSP问题的python版本 # dist 为距离矩阵,start_index 为起始位置 def tsp_quick(dist: list, start_index: int): ...
- branch and bound(分支定界)算法求解TSP旅行商问题
转载自:分枝定界算法求解TSP 整个程序如下所示: 其中各个模块说明如下: - Timer:计时用. - TSPInstanceReader:TSPLIB标准算例读取用. - PriorityQueu ...
- tsp 分支界限 java_干货 | 10分钟教你用branch and bound(分支定界)算法求解TSP旅行商问题...
在此之前,先给大家讲讲最重要的一个点,搜索树的节点定义,节点定义了原问题的solution和子问题的solution.Node节点定义如下: public class Node {private Ar ...
- MATLAB遗传算法GA求解TSP旅行商问题,可选PMX交叉、OX交叉及其它多种交叉方式,在算法中引入2-opt变异算子
MATLAB遗传算法GA求解TSP旅行商问题,可选PMX交叉.OX交叉及其它多种交叉方式,在算法中引入2-opt变异算子.进化逆转算子提高算法局部搜索能力,利用国际通用的TSPLIB数据集中的eil5 ...
- 【路径优化】基于帝企鹅算法求解TSP问题(Matlab代码实现)
目录 1 帝企鹅算法 2 旅行商问题(TSP) 3 运行结果 4 参考文献 5 Matlab代码实现 1 帝企鹅算法 帝企鹅优化算法(emperor penguin optimizer,EPO)是Ga ...
- 蚁群算法求解TSP问题的源代码
蚁群算法求解TSP问题的源代码 分类: 智能算法2014-05-07 17:25 524人阅读 评论(1) 收藏 举报 蚁群算法 TSP win32程序设计 旅行商问题大都是用遗传算法求解,不过蚁群算 ...
最新文章
- (一)win7下cocos2d-x 21 + vs2010
- 软件项目管理0709:一个项目经理对产品方案的迷思
- 操作系统内存管理——分区、页式、段式管理
- Python打造一款多线程端口扫描器
- flexbox 伸缩布局
- 转jpg java源程序_将pdf文件转成图片并删除java源代码
- MySQL 数据库修改登录密码
- 采用C编写程序实现从文件读取操作
- python每行输出8个式子_多图+代码 | 详解Python操作Excel神器openpyxl的各种操作!
- 用python画小黄人-怎么用python画小黄人
- Python入门--以主程序的方式运行,if __name__==‘__main__‘
- macos big sur 11 完整离线安装包v11.5.2正式版
- 2048和多地址入口_七天网站成绩查询官网登录入口地址:http://www.7net.cc/
- Drools(2):Drools快速入门
- 人机交互-任务4:图形交互界面的设计(web)
- YOLOv5中的CSP结构
- 浏览器链接打开客户端应用
- 不能将值 NULL 插入列 'ID',表 列不允许有 Null 值
- 我写代码的这十年——致逝去的青春
- 学法医的写代码,学刑侦的做运营……原来阿里人读过那些奇葩专业!