删除路径后的最短路问题

76 阅读4分钟

import math from heapq import heappush, heappop def solution(n: int, s: int, t: int, x: list, y: list) -> str: def calculate_distance(x1, y1, x2, y2): return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) dist = [[0] * n for _ in range(n)] for i in range(n): for j in range(n): if i != j: dist[i][j] = calculate_distance(x[i], y[i], x[j], y[j]) def dijkstra(start, end): if start == end: min_cycle = float('inf') for mid in range(n): if mid != start-1: cycle_dist = dist[start-1][mid] + dist[mid][start-1] min_cycle = min(min_cycle, cycle_dist) return min_cycle distances = [float('inf')] * n distances[start-1] = 0 pq = [(0, start-1)] visited = set() while pq: d, curr = heappop(pq) if curr in visited: continue visited.add(curr) if curr == end-1: return d for next_node in range(n): if next_node in visited or (curr == s-1 and next_node == t-1) or (curr == t-1 and next_node == s-1): continue new_dist = d + dist[curr][next_node] if new_dist < distances[next_node]: distances[next_node] = new_dist heappush(pq, (new_dist, next_node)) return float('inf') result = dijkstra(s, t) return "{:.2f}".format(result) if name == 'main': print(solution(5, 1, 5, [17253, 25501, 28676, 30711, 18651], [15901, 15698, 32041, 11015, 9733]) == '17333.65') print(solution(4, 2, 4, [5000, 12000, 8000, 14000], [3000, 9000, 1000, 4000]) == '15652.48') print(solution(6, 3, 6, [20000, 22000, 24000, 26000, 28000, 30000], [15000, 13000, 11000, 17000, 19000, 21000]) == '11772.70') 算法分析与思路总结

问题描述

给定一个包含 n 个点的二维平面,点的坐标由 x 和 y 两个列表提供,其中 x[i] 和 y[i] 表示第 i+1 个点的坐标。给定两个点 s 和 t(注意这里的 s 和 t 是基于 1 的索引,而在代码中需要转换为基于 0 的索引),要求计算从点 s 到点 t 的最短路径长度。特别地,如果 s 和 t 相同,则要求找到通过其他点构成的最小环的长度。

算法思路

距离计算:

使用欧几里得距离公式计算任意两点之间的距离,并存储在邻接矩阵 dist 中。

Dijkstra 算法:

经典的 Dijkstra 算法用于计算单源最短路径。

初始化距离数组 distances,将所有点的距离初始化为无穷大,起点 start 的距离初始化为 0。

使用优先队列(最小堆)来维护当前已知最短路径的节点。

每次从优先队列中取出距离最小的节点,更新其相邻节点的最短路径长度。

如果终点 end 被访问到,则返回其最短路径长度。

如果起点和终点相同,则特殊处理:尝试通过每个中间点构建一个环,并找到最小环的长度。

特殊处理起点和终点相同的情况:

当 start == end 时,直接计算通过每个中间点形成的环的长度,并返回最小环的长度。

跳过不允许的直接路径:

在更新最短路径时,跳过从起点直接到终点的路径(如果它们是相邻的),以避免形成不必要的重复计算或错误路径。

算法分析

时间复杂度:

计算邻接矩阵的时间复杂度为 O(n2),因为需要计算每对点之间的距离。

Dijkstra 算法的时间复杂度为 O((n−1)2logn),在最坏情况下,每个节点都需要被访问一次,每次访问都需要从优先队列中取出最小元素(时间复杂度为 O(logn)),并且需要更新所有相邻节点的距离(时间复杂度为 O(n1))。

对于起点和终点相同的情况,计算最小环的时间复杂度为 O(n2),因为需要尝试通过每个中间点构建一个环。

综合考虑,总时间复杂度为 O(n 2+(n−1)2logn),简化后为 O(n2logn)。

空间复杂度:

邻接矩阵 dist 的空间复杂度为 O(n2)。

距离数组 distances 和优先队列 pq 的空间复杂度为 O(n)。

综合考虑,总空间复杂度为 O(n2)。