别再硬算最优路径了!手把手教你用Python模拟退火算法求解TSP(附att48数据集实战)
用Python玩转模拟退火算法48城TSP问题实战指南当面对需要从48个城市中找到最短路径的问题时传统方法往往力不从心。这种被称为旅行商问题TSP的经典难题在物流配送、电路板钻孔等实际场景中无处不在。本文将带你用Python实现模拟退火算法无需复杂数学推导直接获得高质量解决方案。1. 算法原理与工程思维模拟退火算法的精妙之处在于它模仿了金属退火的物理过程。就像铁匠加热金属后缓慢冷却以获得更坚固的结构一样算法通过温度参数控制搜索过程既不会过早陷入局部最优又能最终收敛到理想解。核心优势对比方法类型全局搜索能力收敛速度实现难度穷举法★★★★★★☆☆☆☆★★★☆☆遗传算法★★★☆☆★★★☆☆★★★★☆模拟退火★★★★☆★★★★☆★★☆☆☆金属退火过程与算法参数的对应关系初始温度 → 搜索范围冷却速率 → 收敛速度终止温度 → 解的质量# 算法基本框架 def simulated_annealing(): current_solution random_solution() current_cost calculate_cost(current_solution) temperature INITIAL_TEMP while temperature FINAL_TEMP: new_solution perturb(current_solution) new_cost calculate_cost(new_solution) if acceptance_probability(current_cost, new_cost, temperature) random(): current_solution new_solution current_cost new_cost temperature * COOLING_RATE实际工程中温度下降不宜过快。过快的冷却会导致淬火效应算法容易陷入局部最优解。2. ATT48数据集实战准备ATT48是TSP问题的标准测试数据集包含美国48个州首府的坐标位置。其已知最优解为33523欧式距离未取整。数据预处理关键步骤坐标数据加载import numpy as np cities { 0: (6734, 1453), 1: (2233, 10), # ... 完整坐标数据 47: (3023, 1942) }距离矩阵计算def create_distance_matrix(cities): n len(cities) dist_matrix np.zeros((n, n)) for i in range(n): for j in range(n): x1, y1 cities[i] x2, y2 cities[j] dist_matrix[i][j] np.sqrt((x1-x2)**2 (y1-y2)**2) return dist_matrix初始解生成initial_solution np.random.permutation(len(cities))距离矩阵的预先计算能大幅提升算法效率避免重复计算城市间距。3. 算法实现细节剖析3.1 解的空间探索策略采用2-opt局部搜索策略生成新解这种策略特别适合路径优化问题def two_opt_swap(solution): 在路径中随机选择两个点进行逆序 i, j sorted(np.random.choice(len(solution), 2, replaceFalse)) new_solution solution.copy() new_solution[i:j1] solution[i:j1][::-1] return new_solution扰动策略对比单点交换简单但效率低2-opt交换平衡复杂度与效果3-opt交换计算量大但质量高3.2 关键参数调优指南参数设置直接影响算法表现经过多次实验得出的经验值参数推荐范围影响效果初始温度(T0)1e5-1e7越高搜索范围越大耗时增加终止温度(Tf)0.1-1越低解质量越好但收敛速度变慢降温系数(α)0.95-0.99越接近1降温越慢搜索更充分马尔可夫链长度500-2000越长每温度下搜索越彻底耗时增加# 参数设置实例 T0 1e6 # 初始温度 Tf 0.1 # 终止温度 alpha 0.98 # 降温系数 steps 1000 # 每个温度迭代次数3.3 接受准则的实现Metropolis准则决定是否接受劣解的关键实现def acceptance_probability(old_cost, new_cost, temperature): if new_cost old_cost: return 1.0 return np.exp((old_cost - new_cost) / temperature)在高温阶段算法有较大概率接受劣解有助于跳出局部最优随着温度降低逐渐趋向于只接受优化解。4. 完整实现与结果分析4.1 算法主循环def run_sa(cities, T01e6, Tf0.1, alpha0.98, steps1000): dist_matrix create_distance_matrix(cities) current_solution np.random.permutation(len(cities)) current_cost calculate_cost(current_solution, dist_matrix) best_solution current_solution.copy() best_cost current_cost temperature T0 history [] while temperature Tf: for _ in range(steps): new_solution two_opt_swap(current_solution) new_cost calculate_cost(new_solution, dist_matrix) if acceptance_probability(current_cost, new_cost, temperature) np.random.random(): current_solution new_solution current_cost new_cost if current_cost best_cost: best_solution current_solution.copy() best_cost current_cost history.append(best_cost) temperature * alpha return best_solution, best_cost, history4.2 可视化与性能评估收敛过程可视化plt.plot(history) plt.xlabel(Iteration) plt.ylabel(Best Cost) plt.title(SA Convergence) plt.show()路径可视化def plot_solution(solution, cities): x [cities[i][0] for i in solution] [cities[solution[0]][0]] y [cities[i][1] for i in solution] [cities[solution[0]][1]] plt.plot(x, y, o-) plt.show()典型运行结果初始路径长度约160,000优化后路径长度约35,000与已知最优解差距4%-5%4.3 性能优化技巧距离矩阵缓存预先计算并存储所有城市间距增量式计算只计算路径变化部分的距离差并行化尝试在多温度点并行搜索自适应降温根据搜索进度动态调整降温速率# 增量式距离计算优化 def delta_cost(old_solution, new_solution, dist_matrix, old_cost): # 只计算受2-opt交换影响的部分路径 i, j find_diff_positions(old_solution, new_solution) # 计算新旧片段距离差 delta (dist_matrix[new_solution[i-1]][new_solution[i]] dist_matrix[new_solution[j]][new_solution[(j1)%len(new_solution)]]) - \ (dist_matrix[old_solution[i-1]][old_solution[i]] dist_matrix[old_solution[j]][old_solution[(j1)%len(old_solution)]]) return old_cost delta在实际项目中应用该算法解决物流配送问题时将48个城市替换为实际配送点坐标即可。算法表现稳定在合理时间内能得到可接受的近似解比人工规划路径效率提升显著。