Python实现二维点最短路径 修复自定义算法路径点重复问题
自定义路径查找问题排查与修复
给定数据集
import math import itertools names = ['a', 'b', 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'] x = [3, 6, 6, 10, 12, 15, 3, 6, 13, 9, 13, 12] y = [9, 12, 9, 9, 12, 9, 6, 3, 8, 3, 1, 3]
算法规则
需要实现的自定义路径规则如下,起点固定为a:
- 每到一个当前点,先筛选出距离当前点最近的3个未访问点
- 计算两种遍历顺序的累计路径长度:例如最近3点为b、c、d时,分别计算
路径1:当前点→b→c→d、路径2:当前点→c→b→d的总距离 - 比较两个总距离,路径2更短则选c作为下一跳,否则选b作为下一跳
- 移动到选中的下一跳,重复上述流程直到所有点遍历完成
原有代码问题
原有代码接近实现目标,但存在几个核心逻辑错误导致重复点问题:
- 已访问过滤逻辑失效:代码中预留的
backup_list移除已访问点的逻辑被注释,筛选最近点时完全没有排除已经走过的点,直接导致重复点被加入路径 - 累计距离计算逻辑错误:计算两条对比路径长度时,跳点匹配条件写错,没有正确匹配两点间的预计算距离,得到的对比值完全不准确
- 循环终止条件错误:终止判断依赖的
backup_list从未更新长度,判断阈值len(backup_list)-3不符合遍历所有点的终止要求 - 点匹配歧义:原始
names列表存在重复值b,直接用name做键匹配点会出现索引混淆,导致距离匹配错误
原有问题代码
def distance(p1, p2): return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2) def get_hops(): hopes = [] for i in range(len(x)): for j in range(len(y)): dist = distance((x[i], y[i]), (x[j], y[j])) hopes.append({'from': names[i], 'to': names[j], 'dist': dist}) return hopes def get_points(points): point_1 = points[0] point_2 = points[0] point_3 = points[0] for point in points: if point['dist'] < point_1['dist']: point_1 = point if point['dist'] < point_2['dist'] and point['to'] != point_1['to']: point_2 = point if point['dist'] < point_3['dist'] and point['to'] != point_1['to'] and point['to'] != point_2['to']: point_3 = point return point_1, point_2, point_3 def get_optimal_path(names_list): backup_list = [] for elm in names_list: backup_list.append(elm) points_list = [names_list[0]] backup_list.remove(names_list[0]) hops = get_hops() for elm in itertools.cycle(names_list): if len(points_list) != len(backup_list)-3: print(elm, points_list[-1]) if elm == points_list[-1]: # get closet 3 points to the last point in path hop_1 = {'from': 'qdsofhvcl', 'to': 'qjf', 'dist': 10000000000000} hop_2 = {'from': 'qdsofhvcl', 'to': 'qjf', 'dist': 10000000000000} hop_3 = {'from': 'qdsofhvcl', 'to': 'qjf', 'dist': 10000000000000} for hop in hops: if hop['from'] == elm and hop['to'] != elm and hop['dist'] < hop_1['dist']: hop_1 = hop for hop in hops: if hop['from'] == elm and hop['to'] != elm and hop['dist'] < hop_2['dist'] and hop['to'] != hop_1['to']: hop_2 = hop for hop in hops: if hop['from'] == elm and hop['to'] != elm and hop['dist'] < hop_3['dist'] and hop['to'] != hop_1['to'] and hop['to'] != hop_2['to']: hop_3 = hop # calculate dist_1 and dist_2 to determine optimal hoping point dist_1 = 0 dist_2 = 0 for hop in hops: if hop['from'] == elm and hop['to'] == hop_1['to']: dist_1 += hop['dist'] if hop_1['from'] == hop['from'] and hop_2['to'] == hop['to']: dist_1 += hop['dist'] if hop_2['to'] == hop['from'] and hop['to'] == hop_3['to']: dist_1 += hop['dist'] if hop['from'] == elm and hop['to'] == hop_2['to']: dist_2 += hop['dist'] if hop_2['to'] == hop['from'] and hop_1['to'] == hop['to']: dist_2 += hop['dist'] if hop_1['to'] == hop['from'] and hop['to'] == hop_3['to']: dist_2 += hop['dist'] # compare 2 distances and determine the best hoping point if dist_1 < dist_2: points_list.append(hop_1['to']) print(backup_list) # backup_list.remove(hop_1['to']) else: points_list.append(hop_2['to']) print(backup_list) # backup_list.remove(hop_2['to']) else: print('exit') break print(points_list)
修复后实现(保留原算法逻辑)
修复点对应上述问题,保留原算法的选点、比距逻辑,改用索引做唯一匹配避免重名问题:
def distance(p1, p2): return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2) # 预计算所有点对之间的距离,用索引做唯一键避免重名问题 dist_matrix = [[0]*len(names) for _ in range(len(names))] for i in range(len(names)): for j in range(len(names)): dist_matrix[i][j] = distance((x[i], y[i]), (x[j], y[j])) def get_optimal_path(start_idx=0): visited = [False]*len(names) path = [start_idx] visited[start_idx] = True total_dist = 0 while len(path) < len(names): current = path[-1] # 筛选所有未访问点,按距离从小到大排序 unvisited = [(dist_matrix[current][j], j) for j in range(len(names)) if not visited[j]] unvisited.sort() # 剩余点不足3个时直接补全路径 if len(unvisited) <=3: for _, idx in unvisited: path.append(idx) total_dist += dist_matrix[current][idx] current = idx visited[idx] = True break # 取最近的3个未访问点 _, p1 = unvisited[0] _, p2 = unvisited[1] _, p3 = unvisited[2] # 计算两种顺序的累计距离 dist1 = dist_matrix[current][p1] + dist_matrix[p1][p2] + dist_matrix[p2][p3] dist2 = dist_matrix[current][p2] + dist_matrix[p2][p1] + dist_matrix[p1][p3] # 选更优的下一跳 next_p = p1 if dist1 < dist2 else p2 path.append(next_p) total_dist += dist_matrix[current][next_p] visited[next_p] = True # 转换为name输出,重名点加索引区分 path_name = [f"{names[i]}(idx:{i})" if names.count(names[i])>1 else names[i] for i in path] return path_name, total_dist # 运行测试 path, total = get_optimal_path() print("最终路径:", path) print("总路径长度:", round(total,2))
运行后输出无重复点,完全符合预设算法规则。
内容的提问来源于stack exchange,提问作者Adam Demo_Fighter
相关产品推荐
相关产品推荐

