
一句话介绍:
给定一组城市坐标,这个程序会自动搜索访问所有城市的顺序,在“每个城市访问一次、最后回到起点”的条件下,不断优化路线长度,并最终画出当前搜索到的最短巡回路线以及算法的收敛过程。
假设现在有几十个城市,需要从其中一个城市出发:
每个城市都要访问一次;
不能遗漏城市;
最后还要回到起点;
希望总路程尽可能短。
如果只有几个城市,还可以人工尝试不同顺序。
但随着城市数量增加,可选的访问顺序会迅速增多。对于 (n) 个城市,可能的排列规模按 (n!) 增长,城市一多,靠人工枚举就不现实了。
这个程序的作用就是:
把“城市访问顺序”当成一个需要优化的解,利用粒子群的群体搜索思想不断尝试、比较和更新,自动寻找更短的巡回路线。
程序的整体过程可以理解为:
城市坐标
↓
生成多条随机路线
↓
计算每条路线总长度
↓
粒子根据自身最好路线和群体最好路线调整访问顺序
↓
不断迭代寻找更短路线
↓
输出最佳路线 + 收敛曲线
这套 MATLAB 工程并不是单一计算脚本,而是由主程序和多个辅助函数共同完成一套完整的 TSP 路径优化流程。
主要文件包括:
particle_optimization.m:主程序,负责粒子群初始化、迭代、最优解更新和结果输出;
tsp.m:提供城市坐标并计算城市之间的距离矩阵;
CalDist.m:计算某一条巡回路线的总长度;
changeNum.m:根据当前路线和目标路线生成交换操作;
changeFun.m:按照交换序改变城市访问顺序;
randFun.m:以随机方式截取一部分交换操作;
Drawroute.m:把最终城市路线绘制出来。
程序首先根据城市坐标计算任意两个城市之间的欧氏距离。
主程序通过:
得到:
Clist:所有城市的二维坐标;
dislist:任意两座城市之间的距离矩阵。
tsp.m 中已经内置了:
10 城市数据;
30 城市数据;
50 城市数据;
75 城市数据。
当前主程序设置为:
因此默认求解的是 75 城市巡回路径优化问题。
程序不是从一条固定路线开始,而是同时生成多个不同的随机解。
当前设置:
表示种群中有 100 个粒子。
每个粒子都是一条完整的城市访问顺序:
纯文本
例如可以把一个粒子理解成:
100 个粒子就代表 100 种不同的候选路线。
这样程序可以同时从多个方向寻找更短路径,而不是只沿着一条路线不断试错。
对于每一个候选路线,程序都会调用:
CalDist.m 会依次累加相邻城市之间的距离,并且在最后加入:
最后一个城市 → 第一个城市
的距离。
因此程序优化的不是一条开放路径,而是一条完整的闭环路线。
程序真正要最小化的目标就是:
整条巡回路线的总长度。
普通粒子群算法中的“位置”和“速度”通常是连续数值。
但是 TSP 中的解不是一个普通数值,而是一串城市排列。
例如:
不能像普通数值那样直接做加减。
所以这套程序做了一个关键改造:
用“城市位置交换序”代替普通粒子群中的速度。
例如:
执行这些交换后,一条路线就会变成另一条路线。
程序通过 changeNum.m、changeFun.m 和 randFun.m,把粒子群的更新思想转换成适用于城市排列的交换操作。
每个粒子在搜索过程中都会记住:
代码中使用:
保存每个粒子的个体最优路线和对应路线长度。
如果当前找到的新路线更短:
就会更新自己的历史最好记录。
程序还会寻找当前所有粒子中的最短路线:
并保存为:
所以一个粒子的下一步搜索不是完全随机,而是同时参考:
自己过去找到的好路线 + 整个群体目前找到的最好路线。
程序记录两类信息:
分别表示:
当前已经找到的全局最短距离;
当前种群的平均路线长度。
最终程序绘制:
因此运行结束后,不仅能看到最终路线,还能看到:
随着迭代次数增加,最优距离和种群平均距离是如何变化的。
这就是算法的收敛过程。
优化结束后,程序执行:
将每一个城市画成二维平面上的点,再按照搜索得到的最佳访问顺序依次连线。
最后还会连接:
最后一个城市 → 第一个城市
形成完整闭环。
因此程序输出的不是一串难以理解的数字,而是一张可以直接观察的路径图。
如果一个任务需要依次访问很多地点,例如:
多个客户点;
多个检查点;
多个作业位置;
多个采样点;
并且希望总体移动距离较短,那么这类问题就可以抽象成城市巡回路径问题。
程序可以用来研究:
这些地点应该按照什么顺序访问更合适。
例如一个配送员需要访问多个配送点后返回出发位置,或者巡检人员需要依次经过多个设备点。
真正的工程系统通常还会加入:
道路限制;
时间窗;
车辆容量;
实际路网;
优先级;
而当前程序解决的是其中最基础的一层:
只考虑各点之间的距离,寻找较短的访问顺序。
因此它很适合用来学习配送、巡检和调度优化的基础思想。
如果机器人已经知道多个目标点的位置,而问题重点不是避障,而是:
先去哪个点、再去哪个点,整体移动距离更短?
那么就可以采用类似的排列优化思想。
需要注意:
当前程序没有地图障碍物和碰撞检测模块,因此它属于“访问顺序规划”,而不是完整的障碍物路径规划。
这个工程非常适合学习一个重要问题:
连续粒子群算法怎样改造成能够处理排列组合问题的离散算法?
程序没有直接调用现成 TSP 求解器,而是明确写出了:
路线编码;
距离计算;
个体最优;
全局最优;
交换序;
随机保留;
粒子更新;
防止局部最优;
结果绘图。
因此比较适合作为智能优化算法课程或 MATLAB 实验项目。
这套程序的核心思想来自 粒子群优化算法(Particle Swarm Optimization,PSO)。
可以先不记公式,把它想象成:
一群人同时找路。每个人都记得自己走过的最好路线,同时还能看到整个团队目前找到的最好路线。下一轮搜索时,每个人既保留一部分自己的探索方向,又向自己过去的成功经验和团队的成功经验靠近。
不断重复这个过程后,整个群体就有机会逐渐集中到更优的路线附近。
在这份程序里,这个过程被改造成了适用于 TSP 的离散版本。
普通 PSO 中,一个粒子的位置可能是:
而在这里,一个粒子的位置是:
它表示城市的访问顺序。
这样一来:
粒子的位置,就是一条完整路线。
连续空间中,速度可以直接改变数值。
但排列问题不能直接做普通加减,因此程序定义:
速度 = 一组位置交换操作。
changeFun.m 会按顺序执行这些交换:
因此,粒子移动的过程实际上就是:
不断交换路线中城市的位置。
程序通过:
构造一组让当前路线向“个体历史最好路线”靠近的交换操作。
然后通过:
随机保留其中一部分操作,再执行到当前路线。
这相当于:
粒子不完全复 制过去的最好路线,而是吸收其中一部分结构。
类似地:
让当前粒子吸收一部分全局最佳路线的信息。
因此每一次更新都同时受到:
原有运动趋势 + 个体历史经验 + 群体最佳经验
的共同影响。
每生成一个新排列,程序都重新计算路线总长度:
路线越短,说明这个解越好。
所以整个搜索过程始终围绕一个明确目标进行:
让总巡回距离不断减小。
如果只维护一条路线,那么一次错误搜索可能会把算法带到不好的方向。
粒子群同时维护很多个候选解。
当前程序默认:
即 100 条路线同时搜索。
理论上,这带来的价值是:
不同粒子可以探索解空间中的不同区域。
有的粒子可能在当前好路线附近继续优化,有的粒子可能还在较远位置探索。
相比只维护一个解,群体搜索通常更容易获得更丰富的搜索方向。
粒子群算法的一个核心机制是 个体最优记忆。
每个粒子都保存自己历史上找到的最好解。
这意味着:
即使下一次随机交换产生了一条更差路线,粒子也不会忘记自己之前找到过的好路线。
程序用:
保存这些信息。
理论上的好处是:
随机探索不会完全破坏历史经验。
如果某一个粒子找到了一条明显更短的路线,程序会更新:
之后其他粒子的更新都会参考这个全局最好路线。
这相当于:
一个粒子的成功,可以转化成整个种群的搜索方向。
所以粒子群并不是 100 个互不相关的随机搜索,而是一个具有信息共享机制的群体优化过程。
TSP 最重要的约束是:
每个城市必须恰好出现一次。
如果直接对城市编号做普通数值加减,例如把城市编号乘 0.5、加 2.3,就会产生没有意义的路线。
而交换操作有一个非常重要的性质:
无论交换多少次,原来的排列仍然是一个合法排列。
例如:
交换第 2、4 位后:
仍然包含:
每个城市仍然只出现一次。
因此,“交换序”把粒子群从连续空间改造成离散排列空间时,能够天然保持 TSP 解的合法性。
randFun.m 并不会机械执行完整交 换序,而是随机保留其中一部分交换操作。
也就是说,粒子不会一次性完全 复 制:
自己过去的最优路线;
或整个群体的最优路线。
这种随机性很重要。
如果所有粒子都立即复 制同一个当前最优解,那么种群很快就会变得完全一样,后面就很难继续探索新的路线。
随机截取交换操作,相当于让粒子:
一部分跟随经验,一部分保留自己的变化。
这有助于在:
向好路线靠近
和
继续尝试新路线
之间保持一定平衡。
主程序定义:
分别参与:
当前交换序的随机保留;
个体历史最好方向的交换;
全局最好方向的交换。
从粒子群思想上看,这三个部分分别对应:
不要让粒子每一轮都完全改变搜索方式。
参考“我自己以前在哪里找到过好路线”。
参考“整个群体现在在哪里找到最好路线”。
这三类信息共同决定下一条候选路线,使搜索不再是纯随机枚举。
程序中还有一个专门的处理:
程序设计意图是:
当粒子已经与当前全局最好位置重合时,重新随机生成一条路线。
这样做的目的不是进一步复 制当前最优解,而是重新释放一部分搜索能力。
理论上可以理解为:
当种群过度集中时,引入新的随机解,提高继续发现其他更优区域的机会。
这正是在启发式优化中常见的“增加多样性”思想。
最直接的方法当然是:
把所有可能的城市访问顺序全部计算一遍,然后选最短的。
这种方法的优点是简单,而且如果全部枚举完成,就能找到真正的最优解。
问题在于:
候选路线数量按阶乘增长。
城市数量从 10 增加到几十以后,所有排列的数量会迅速变得极大。
当前程序默认求解:
对于这种规模,穷举全部排列并不现实。
粒子群方法采用的是另一种思路:
不检查所有路线,而是通过群体经验和随机搜索,把有限计算资源集中到更有希望的路线区域。
因此它属于:
启发式近似优化
而不是:
穷举式精确搜索。
需要特别说明:
粒子群算法可以搜索到很短的路线,但并不能仅凭当前程序保证每次运行都得到理论上的全局最优路线。
另一种简单办法是:
随机生成路线;
计算路线长度;
一直保存目前最短的。
这种方法虽然也能探索很多路线,但每一次随机尝试之间几乎没有信息传递。
而当前粒子群程序会保存:
个体历史最好路线;
全局历史最好路线;
当前粒子的交换趋势。
因此它和纯随机搜索最大的区别是:
之前搜索得到的经验会参与下一轮路线生成。
搜索不是每一轮重新“从零开始”。
程序直接使用城市二维坐标,并自动生成距离矩阵。
用户容易理解:
城市在哪里 → 路线多长 → 哪条路线更短。
工程已经包含:
城市数据 → 距离计算 → 路线初始化 → 粒子群迭代 → 最优路线 → 路径绘制 → 收敛曲线
因此不是只有核心算法片段,而是一套可以完整展示搜索过程的 MATLAB 示例。
tsp.m 中内置:
修改:
即可切换已有数据规模。
这使程序比较适合做算法规模变化实验。
主程序开头集中设置:
因此可以比较方便地研究:
粒子数变化;
迭代次数变化;
学习参数变化;
城市规模变化;
对最终路线和收敛速度的影响。
最终程序输出两个主要图形:
直接观察算法找到的城市访问路线。
比较:
全局最短距离;
种群平均距离。
所以不仅知道“最后找到什么”,还可以观察:
算法是怎样逐步逼近更短路线的。
确保下面这些 .m 文件位于 MATLAB 当前工作目录中:
运行入口是:
默认参数为:
其中:
对于第一次运行,可以先保持默认设置。
如果希望快速测试,也可以在理解代码后适当减小:
以减少计算量。
点击 MATLAB 的“运行”。
程序会自动完成:
加载城市坐标;
计算城市距离;
随机生成粒子;
计算初始路线长度;
进行交换序粒子群迭代;
更新个体最好路线;
更新全局最好路线;
记录每轮最短和平均距离;
绘制最终路线;
绘制收敛曲线。
程序执行:
将 75 个城市绘制成散点,并根据最终 R_best 的访问顺序连接。
因此可以直接看到:
程序最终选择了怎样的城市访问顺序。
程序执行:
可以观察:
当前最好路线长度是否逐渐下降;
整个粒子群的平均路线是否发生改善;
后期算法是否趋于稳定。
这张图能够直观体现粒子群搜索过程,而不是只给出最终数字。
tsp.m 中已经直接写入了 75 个城市的二维坐标,并在代码注释中给出了该数据对应的参考值:
这里可以把它理解为该城市数据集随代码附带的一个参考路线长度信息。
程序会根据随机初始化和粒子群迭代实际搜索自己的路线。
由于当前算法属于随机启发式优化:
不同运行过程可能产生不同的搜索轨迹和最终结果,不能把代码注释中的参考值直接当成程序每次运行必然得到的结果。
程序使用的是二维城市点之间的欧氏距离。
它没有实现:
障碍物地图;
碰撞检测;
A* 栅格搜索;
道路可行性判断。
因此更加准确的说法是:
多城市访问顺序优化 / TSP 路径规划。
tsp.m 中使用:
计算两个城市之间的欧氏距离。
因此程序默认认为:
两点之间可以直接连接。
如果用于真实道路配送,还需要把距离矩阵替换为实际道路距离或行驶时间。
初始化路线使用:
交换序的保留也使用:
因此不同运行可能得到不同结果。
这属于随机智能优化算法的正常特征。
程序会不断保留更短路线,但没有数学机制证明最终结果一定是全局最优。
更准确的表述是:
在给定粒子数、参数和迭代次数下搜索较优的巡回路线。
tsp.m 中的当前程序已经预置 10、30、50、75 城市数据。
如果需要规划自己的地点,需要进一步:
替换城市坐标;
或直接提供新的距离矩阵;
保证 CityNum 与数据规模一致。
这是一个面向旅行商问题的 MATLAB 离散粒子群路径优化程序:它把一条城市访问路线表示成一个粒子,把交换城市顺序表示成粒子的“速度”,再让大量候选路线同时参考自身历史最好路线和群体最好路线不断搜索,最终得到一条较短的闭环巡回路线,并用路径图和收敛曲线展示优化结果。