# Summary # Cues # Notes # 路线优化算法详解 ## 算法概述 本系统实现了一个**带固定起终点的旅行商问题(TSP)**变体求解器。核心目标是在给定多个可选的起终点和必须访问的POI点的情况下,找到总距离最短的路径。 ## 问题定义 ### 输入 - **交通站点列表**(2-3个):可作为起点或终点 - **POI列表**(1-20个):必须访问的兴趣点 ### 输出 - **最优路径**:包含起点、所有POI、终点的有序列表 - **总距离**:路径的总长度 - **起终点选择**:最优的起点和终点组合 ## 算法流程 ### 1. 主流程(solve_route方法) ```python def solve_route(transit_points, pois): # 步骤1:合并所有点并建立索引 all_points = transit_points + pois # 步骤2:构建距离矩阵 dist_matrix = build_distance_matrix(all_points) # 步骤3:枚举所有可能的起终点组合 for start, end in all_combinations(transit_points): # 步骤4:对每个组合求解TSP route = solve_tsp(start, end, pois, dist_matrix) # 步骤5:应用局部优化 route = optimize_with_2opt(route, dist_matrix) # 步骤6:记录最优解 if is_better(route): best_route = route return best_route ``` ### 2. 核心算法选择 系统根据POI数量选择不同的算法: #### 当POI数量 ≤ 15:动态规划算法 **时间复杂度**:O(n²·2ⁿ) **空间复杂度**:O(n·2ⁿ) **特点**:保证找到全局最优解 ##### 动态规划状态定义 ```Java dp[mask][i] = 从起点出发,访问了mask中的点,最后到达点i的最短距离 ``` 其中: - `mask`:二进制表示已访问的POI集合 - `i`:当前所在的POI索引 ##### 状态转移方程 ```Java dp[mask][i] = min(dp[prev_mask][j] + dist[j][i]) 其中:prev_mask = mask ^ (1 << i),j是prev_mask中的任意点 ``` ##### 详细实现逻辑 1. **初始化**: ```python # 从起点直接到达每个POI for i in range(n): mask = 1 << i # 只访问了第i个点 dp[mask, i] = dist[start][poi[i]] ``` 2. **填表过程**: ```python # 遍历所有可能的访问状态 for mask in range(1, 1 << n): # 遍历当前状态的最后一个点 for last in range(n): if not (mask & (1 << last)): continue # 计算到达last的最优路径 prev_mask = mask ^ (1 << last) for prev in range(n): if (prev_mask & (1 << prev)): # 从prev到last的转移 dp[mask][last] = min( dp[mask][last], dp[prev_mask][prev] + dist[prev][last] ) ``` 3. **构造最优解**: ```python # 找到访问所有点后到终点的最短路径 full_mask = (1 << n) - 1 min_dist = inf for i in range(n): dist = dp[full_mask][i] + dist[poi[i]][end] if dist < min_dist: min_dist = dist last_poi = i ``` #### 当POI数量 > 15:最近插入法 **时间复杂度**:O(n²) **空间复杂度**:O(n) **特点**:快速得到近似解 ##### 算法步骤 1. **初始化**:创建只包含起点和终点的路径 2. **迭代插入**: ```python while 还有未访问的POI: best_poi = None best_position = None best_increase = inf for poi in unvisited: for position in route: # 计算插入poi到position的距离增加 increase = dist[prev][poi] + dist[poi][next] - dist[prev][next] if increase < best_increase: best_increase = increase best_poi = poi best_position = position # 插入最优POI route.insert(best_position, best_poi) ``` ### 3. 局部优化:2-opt算法 无论使用哪种算法得到初始解,都会应用2-opt优化来改进路径质量。 **原理**:通过反转路径中的子段来减少交叉,降低总距离。 ```python def optimize_with_2opt(route, dist_matrix): improved = True while improved: improved = False for i in range(1, len(route) - 2): # 不动起点 for j in range(i + 1, len(route) - 1): # 不动终点 # 计算反转[i:j+1]的收益 old_dist = dist[i-1][i] + dist[j][j+1] new_dist = dist[i-1][j] + dist[i][j+1] if new_dist < old_dist: # 反转子路径 route[i:j+1] = route[i:j+1][::-1] improved = True break ``` ## 实际案例演示 ### 输入示例(北京旅游) ```python transit_points = [ {"id": "t1", "name": "北京站", "lat": 39.9075, "lng": 116.4272}, {"id": "t2", "name": "北京西站", "lat": 39.8948, "lng": 116.3229} ] selected_pois = [ {"id": "p1", "name": "故宫", "lat": 39.9163, "lng": 116.3972}, {"id": "p2", "name": "天安门", "lat": 39.9055, "lng": 116.3976}, {"id": "p4", "name": "天坛", "lat": 39.8822, "lng": 116.4066} ] ``` ### 算法执行过程 1. **构建距离矩阵**(5×5): ```Java 北京站 北京西站 故宫 天安门 天坛 北京站 0 11.5 3.2 2.8 4.6 北京西站 11.5 0 10.1 9.8 9.2 故宫 3.2 10.1 0 1.2 4.3 天安门 2.8 9.8 1.2 0 3.1 天坛 4.6 9.2 4.3 3.1 0 ``` 2. **枚举起终点组合**: - 组合1:北京站 → POIs → 北京西站 - 组合2:北京西站 → POIs → 北京站 - 组合3:北京站 → POIs → 北京站 - 组合4:北京西站 → POIs → 北京西站 3. **对每个组合运行动态规划**: 以组合1为例(北京站 → POIs → 北京西站): - 状态空间:3个POI,共2³=8种访问状态 - 初始化: - dp[001, 0]= 3.2(北京站→故宫) - dp[010, 1]= 2.8(北京站→天安门) - dp[100, 2]= 4.6(北京站→天坛) - 状态转移: - dp[011, 0]= dp[010, 1]+ dist[天安门][故宫]= 2.8 + 1.2 = 4.0 - dp[011, 1]= dp[001, 0]+ dist[故宫][天安门]= 3.2 + 1.2 = 4.4 - ... - 最终状态: - dp[111, 0]= 7.1(访问所有POI,最后在故宫) - dp[111, 1]= 6.9(访问所有POI,最后在天安门) - dp[111, 2]= 8.3(访问所有POI,最后在天坛) - 到达终点: - 故宫→北京西站:7.1 + 10.1 = 17.2 - 天安门→北京西站:6.9 + 9.8 = 16.7 ✓(最优) - 天坛→北京西站:8.3 + 9.2 = 17.5 4. **路径重建**: 通过parent数组回溯得到: ```Java 北京站 → 天安门 → 故宫 → 天坛 → 北京西站 总距离:16.7 km ``` 5. **2-opt优化**: 检查是否有交叉路径可以优化,本例中路径已是最优。 ### 最终输出 ```json { "route": [ {"name": "北京站", "type": "transit"}, {"name": "天安门", "type": "poi"}, {"name": "故宫", "type": "poi"}, {"name": "天坛", "type": "poi"}, {"name": "北京西站", "type": "transit"} ], "total_distance": 16.7, "start_point": "北京站", "end_point": "北京西站" } ``` ## 算法优化策略 ### 1. 剪枝优化 - 在动态规划中,如果当前距离已超过已知最优解,提前终止 ### 2. 启发式改进 - 使用最近邻启发式生成初始解 - 应用多种局部搜索算法(2-opt, 3-opt) ### 3. 并行化 - 不同起终点组合可以并行计算 - 动态规划的某些状态可以并行更新 ## 性能分析 | POI数量 | 算法选择 | 时间复杂度 | 解的质量 | |---------|----------|------------|----------| | ≤15 | 动态规划 | O(n²·2ⁿ) | 最优解 | | 16-25 | 最近插入+2-opt | O(n²) | 近似最优(误差<10%) | ## 实际应用建议 1. **小规模问题(≤15个POI)**: - 使用动态规划保证最优解 - 适合对路径质量要求高的场景 2. **中等规模问题(16-25个POI)**: - 使用启发式算法+局部优化 - 在可接受时间内得到高质量解 3. **实时应用**: - 缓存常见查询结果 - 使用增量更新策略 ## 扩展方向 1. **时间窗口约束**:某些POI只在特定时间开放 2. **容量约束**:考虑交通工具的容量限制 3. **多日行程**:将行程分配到多天 4. **实时路况**:集成实时交通信息调整路线 5. **用户偏好**:根据用户历史偏好调整POI权重