Python实战:用NetworkX可视化TSP问题,手把手教你实现最邻近与插入算法
Python实战用NetworkX可视化TSP问题手把手教你实现最邻近与插入算法当你在规划一次跨越多个城市的旅行路线时如何找到最短的路径这就是经典的旅行商问题TSP。作为组合优化领域的著名难题TSP在物流配送、电路板钻孔、DNA测序等领域都有广泛应用。本文将带你用Python的NetworkX库通过可视化方式直观理解两种经典近似算法——最邻近方法和最邻近插入法。1. 环境准备与问题建模在开始编码前我们需要搭建开发环境并理解如何用图论建模TSP问题。推荐使用Anaconda创建Python 3.8环境安装以下核心库pip install networkx matplotlib numpyTSP问题可以抽象为一个加权完全无向图每个城市代表图中的一个节点城市间的距离表示为边的权重目标是找到总权重最小的哈密顿回路经过每个节点一次且返回起点用NetworkX创建随机城市网络的代码示例import networkx as nx import numpy as np def generate_random_cities(num_cities, seed42): np.random.seed(seed) G nx.complete_graph(num_cities) for u, v in G.edges(): G.edges[u,v][weight] np.random.randint(50, 200) return G # 生成10个城市的随机距离矩阵 cities_graph generate_random_cities(10)2. 最邻近方法实现与可视化最邻近方法(Nearest Neighbor)是一种贪心算法其核心思想是每次选择距离当前城市最近的未访问城市作为下一站。让我们分解实现步骤算法流程选择任意起点城市重复以下步骤直到访问所有城市找到距离当前城市最近的未访问城市移动到该城市并标记为已访问最后返回起点完成回路Python实现关键代码def nearest_neighbor_tsp(G, start_node0): unvisited set(G.nodes) current start_node unvisited.remove(current) path [current] while unvisited: # 找到最近的未访问邻居 neighbors [(n, G.edges[current,n][weight]) for n in G.neighbors(current) if n in unvisited] next_node min(neighbors, keylambda x: x[1])[0] path.append(next_node) unvisited.remove(next_node) current next_node # 返回起点完成回路 path.append(start_node) return path可视化对比不同起点的选择会导致不同的解质量。下图展示了从城市0和城市3出发的结果对比import matplotlib.pyplot as plt def plot_tsp_solution(G, path, title): pos nx.circular_layout(G) nx.draw(G, pos, with_labelsTrue) # 绘制路径 path_edges list(zip(path[:-1], path[1:])) nx.draw_networkx_edges(G, pos, edgelistpath_edges, edge_colorr, width2) plt.title(title) plt.show() # 从不同起点出发的对比 path1 nearest_neighbor_tsp(cities_graph, 0) path2 nearest_neighbor_tsp(cities_graph, 3) plot_tsp_solution(cities_graph, path1, 起点为城市0的最邻近解) plot_tsp_solution(cities_graph, path2, 起点为城市3的最邻近解)注意最邻近方法的时间复杂度为O(n²)适合中小规模问题但解的质量受起点影响较大通常不是最优解。3. 最邻近插入法进阶实现为了改进最邻近方法的不足我们引入最邻近插入法。这种方法通过动态调整现有路径来获得更好的近似解算法优势不受初始起点选择的显著影响通常能获得比简单最邻近方法更优的解仍保持多项式时间复杂度分步实现def nearest_insertion_tsp(G): # 初始选择一个节点作为回路 nodes list(G.nodes) tour [nodes[0], nodes[0]] while len(tour) len(nodes): # 找到距离当前回路最近的节点 min_dist float(inf) nearest_node None for node in set(nodes) - set(tour[1:-1]): for tour_node in tour[:-1]: dist G.edges[node, tour_node][weight] if dist min_dist: min_dist dist nearest_node node # 在所有可能位置插入选择最优的 best_tour None best_length float(inf) for i in range(1, len(tour)): new_tour tour[:i] [nearest_node] tour[i:] length calculate_tour_length(G, new_tour) if length best_length: best_length length best_tour new_tour tour best_tour return tour def calculate_tour_length(G, path): return sum(G.edges[u,v][weight] for u,v in zip(path[:-1], path[1:]))性能对比实验我们可以系统比较两种算法的表现# 生成多个随机实例进行测试 results [] for _ in range(10): G generate_random_cities(15, seednp.random.randint(100)) # 测试最邻近方法取不同起点中的最佳解 nn_lengths [] for start in range(5): # 尝试5个不同起点 path nearest_neighbor_tsp(G, start) nn_lengths.append(calculate_tour_length(G, path)) # 测试插入法 ni_path nearest_insertion_tsp(G) results.append({ nn_best: min(nn_lengths), ni: calculate_tour_length(G, ni_path) }) # 计算平均改进比例 improvements [(r[nn_best]-r[ni])/r[nn_best] for r in results] avg_improvement np.mean(improvements) * 100 print(f插入法平均比最邻近方法优化了{avg_improvement:.1f}%)典型输出显示插入法通常能比最邻近方法优化5-15%的路径长度。4. 算法优化与扩展应用掌握了基础实现后我们可以进一步优化算法并探索实际应用场景性能优化技巧使用优先队列加速最近邻搜索对大规模问题采用分治策略缓存距离计算减少重复工作混合策略实现def hybrid_tsp(G, num_starts5): 结合最邻近方法和插入法的混合策略 best_tour None best_length float(inf) for start in range(min(num_starts, len(G.nodes))): # 先用最邻近方法生成初始解 nn_tour nearest_neighbor_tsp(G, start) # 再用插入法优化 current_tour nn_tour[:-1] # 去掉重复的起点 improved_tour nearest_insertion_tsp(G, initial_tourcurrent_tour) length calculate_tour_length(G, improved_tour) if length best_length: best_length length best_tour improved_tour return best_tour实际应用调整处理非对称距离矩阵如单行道情况加入时间窗口约束考虑多旅行商场景可视化进阶技巧使用交互式绘图可以更好地理解算法过程import matplotlib.animation as animation def animate_tsp_construction(G, path_generator): fig, ax plt.subplots(figsize(10, 6)) pos nx.circular_layout(G) def update(frame): ax.clear() nx.draw(G, pos, axax, with_labelsTrue) current_path path_generator.send(frame) path_edges list(zip(current_path[:-1], current_path[1:])) nx.draw_networkx_edges(G, pos, edgelistpath_edges, edge_colorr, width2, axax) ax.set_title(fStep {frame}) ani animation.FuncAnimation(fig, update, frameslen(G.nodes), interval800, repeatFalse) plt.close() return ani # 使用生成器逐步产生路径 def path_generator(G, algorithm): path [] for step in algorithm(G): path step yield path yield path [path[0]] # 闭合回路 # 生成动画 ani animate_tsp_construction(cities_graph, path_generator(cities_graph, stepwise_nearest_neighbor)) HTML(ani.to_jshtml())这种动态可视化能清晰展示算法每一步的决策过程特别适合教学演示。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2550266.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!