AI 刷题 349. 删除路径后的最短路问题 题解 | 豆包MarsCode AI刷题

77 阅读4分钟

最短路径问题:寻找通过其他点绕行的最短路线

问题描述

在一个平面地图上标记了若干个点,每个点都有其二维坐标。通常情况下,任意两点之间都存在一条直线路径,其长度等于两点间的欧几里得距离。现在,由于某些原因,起点和终点之间的直接路径不可用。我们需要计算从起点到终点,允许通过其他点绕行,但不能通过直接的起终点路径的最短距离。

核心思路

本问题的核心在于使用图论中的最短路径算法来解决,具体而言,使用了迪杰斯特拉(DijkstraDijkstra)算法。算法的主要难点在于处理特殊情况,即直接从起点到终点的路径不可用。这要求我们在算法执行过程中,避免通过该直线路径。

滑动窗口解析

滑动窗口算法:对于每个点,计算与其他所有点之间的距离,并存储这些值。使用一个优先队列(最小堆)来维护当前未处理的最短路径。

字符替换计数:在处理过程中,我们确保不通过直接的起点至终点路径,这可以通过在遍历邻接点时加以判断来实现。

计算并更新最大长度:通过维护一个距离数组,记录从起点到每一个点的最短距离,从而找到从起点到终点的最短路径。

算法详解

在实现时,首先初始化所有点之间的距离矩阵。接着,通过DijkstraDijkstra算法,从起点开始,更新通过各点到达其他点的最短路径长度。关键在于,每次从优先队列中取出当前最短路径的点时,跳过那些不符合条件的路径(即直接从起点到终点的路径)。

复杂度分析

  • 时间复杂度:主要消耗在两个方面,一是初始化距离矩阵,其复杂度为 O(n2)O(n^2),二是DijkstraDijkstra算法本身,复杂度为 O((n2+n)logn)O((n^2 + n) \log n),因为每个节点都可能进出优先队列。
  • 空间复杂度:主要消耗在存储距离矩阵和优先队列,总体为 O(n2)O(n^2)

Code(Python代码)

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

        dis = [float('inf')] * n
        dis[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 < dis[next_node]:
                    dis[next_node] = new_dist
                    heappush(pq, (new_dist, next_node))

        return float('inf')
    res = dijkstra(s, t)
    return "{:.2f}".format(res)

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')
    print(solution(10, 2, 2, [11,3,5,6,2,4,15,14,16,8], 
                   [5,8,7,14,8,10,5,4,2,9]) == '2.00')

实际应用

该算法不仅适用于理论中的最短路径问题,也可以扩展到现实世界中的路线规划,特别是在某些路径不可用或存在临时维修的情况下。例如,在交通导航系统中,经常需要绕过某些因交通事故或施工关闭的路段。

思考与挑战

尽管DijkstraDijkstra算法非常有效,但在节点数量非常大时,其性能可能会受到影响。一个可能的改进方案是采用更高效的算法,如AA*或者是FloydWarshallFloyd-Warshall算法,后者可以同时处理所有点对的最短路径问题,特别适用于点数量不是非常大,但需要频繁查询任意两点间最短路径的场景。

总结

通过使用豆包MarsCode AI刷题工具,我在解题速度、知识梳理和错题复盘方面取得了显著进步。接下来的学习计划将继续结合AI的智能辅助与经典资源,进一步夯实基础知识并挑战更复杂的题目。

希望我的总结能帮助到其他初学者,一起享受算法学习的过程!