📜  门| GATE-IT-2004 |问题 33(1)

📅  最后修改于: 2023-12-03 15:12:44.721000             🧑  作者: Mango

门 | GATE-IT-2004 | 问题 33

题目描述

给定一个无向图 $G=(V,E)$ 和一个起点 $s$,请实现一个函数 shortest_path(u: int, v: int, G: Dict[int, List[int]], s: int) -> Tuple[List[int], float],用于计算从点 $u$ 到点 $v$ 的最短路径。其中 $G$ 为邻接表表示,键值为节点编号,值则为跟该节点直接相连的节点组成的列表。同时,每条边都有一个边权值,每个边权值均为正实数。

函数需要返回一个二元组,第一个元素为从 $u$ 到 $v$ 的路径(以列表形式存储),第二个元素为总路径长度。

示例
G = {
  1: [2, 3],
  2: [1, 3, 4],
  3: [1, 2, 4],
  4: [2, 3]
}
s = 1
shortest_path(1, 4, G, s)

输出:

([1, 2, 4], 3.0)
思路

本题属于图论算法的基础题目,可以使用 Dijkstra 算法或 Bellman-Ford 算法求解最短路径。

在本题中,我们使用 Dijkstra 算法。具体思路如下:

  1. 初始化一个距离数组 dist,每个元素初始化为正无穷。
  2. 将起点 $s$ 对应的距离赋为 0,并将其加入到已访问节点的集合 visited 中。
  3. 对于与起点 $s$ 相邻的节点 $v$,更新该节点到起点 $s$ 的距离。同时,将 $v$ 加入到堆 heap 中。
  4. 从堆 heap 中取出当前距离起点最短的节点 $u$,将其加入到已访问节点的集合 visited 中,并更新与其相邻节点的距离。同时,将这些相邻节点加入到堆 heap 中。
  5. 重复步骤 4,直到堆 heap 中没有节点或者当前取出的节点为 $v$。
代码实现
import heapq
from typing import Dict, List, Tuple

def shortest_path(u: int, v: int, G: Dict[int, List[int]], s: int) -> Tuple[List[int], float]:
    # 起点的距离赋为 0
    dist = {i: float('inf') for i in G}
    dist[s] = 0
    heap = [(0, s)]
    visited = set()
    while heap:
        d, u = heapq.heappop(heap)
        if u == v:
            break
        if u in visited:
            continue
        visited.add(u)
        for w in G[u]:
            if w in visited:
                continue
            if dist[w] > dist[u] + 1:
                dist[w] = dist[u] + 1
                heapq.heappush(heap, (dist[w], w))
    if dist[v] == float('inf'):
        return [], 0.0
    path = [v]
    while v != u:
        for w in G[v]:
            if dist[w] < dist[v]:
                path.append(w)
                v = w
                break
    return path[::-1], dist[path[-1]]
复杂度分析

本算法的时间复杂度为 $O(|E|\log|V|)$,其中 $|V|$ 为节点数目,$|E|$ 为边数目。该算法在最糟糕的情况下需要遍历所有的边和节点。空间复杂度为 $O(|V|)$,用于存储距离数组 dist