📜  门| GATE CS 2012 |问题24(1)

📅  最后修改于: 2023-12-03 14:58:19.713000             🧑  作者: Mango

门 | GATE CS 2012 | 问题24

这道问题考察了对于图遍历的基础知识,需要找到从给定起点到给定终点的最短路径。

问题描述

给定一个无向图 $G=(V,E)$,每一条边 $e \in E$ 都有权重 $c(e)$,且对于 $1 \leq i,j \leq n$,若 $(i,j) \notin E$,则 $c(i,j)=\infty$。给定起点 $s$ 和终点 $t$,请实现一个算法来找到 $s$ 到 $t$ 的最短路径。

解题思路

本题可以通过 Dijkstra 算法来解决。Dijkstra 算法的基本思想是维护一个集合 $S$,它包含已经找到最短路径的点,以及与这些点相邻的点。一开始, $S$ 只包含起点 $s$,并且到所有点的距离都为无穷大。随着算法的进行,将新的点加入到 $S$ 中,并更新与 $S$ 中的点相邻的点的距离。不断迭代这个过程,直到终点 $t$ 被加入到 $S$ 中,或者所有点都已加入。

具体实现时,可以使用一个优先队列来保存距离当前点最近的点。在每次从队列中取出一个点后,更新与该点相邻的点的距离,然后将它们加入到队列中。

最终,如果要输出路径,需要在更新过程中维护一个前驱数组 $p$,保存每一个点的前驱。

代码实现

以下是使用 Python 语言实现 Dijkstra 算法的代码:

import heapq

def dijkstra(n, adj, s, t):
    d = [float('inf')] * n
    d[s] = 0
    p = [-1] * n

    q = []
    heapq.heappush(q, (0, s))

    while q:
        dist, u = heapq.heappop(q)
        if u == t:
            break
        if d[u] < dist:
            continue
        for v, w in adj[u]:
            if d[u] + w < d[v]:
                d[v] = d[u] + w
                p[v] = u
                heapq.heappush(q, (d[v], v))

    if d[t] == float('inf'):
        return []
    else:
        path = []
        while t != -1:
            path.append(t)
            t = p[t]
        return path[::-1]

其中,n 表示节点数,adj 是图的邻接表表示,s 表示起点,t 表示终点。邻接表的形式为:

adj = [[] for _ in range(n)]
for i in range(m):
    u, v, w = map(int, input().split())
    adj[u-1].append((v-1, w))
    adj[v-1].append((u-1, w))

对于每个节点,邻接表中存储了与它相邻的点及其权重。

使用方式为:

path = dijkstra(n, adj, s, t)
if path:
    print(*path)
else:
    print(-1)

如果找到了最短路径,输出路径经过的节点;否则输出 -1。

算法分析

Dijkstra 算法的时间复杂度为 $O((m+n)\log n)$,其中 $m$ 是边数,$n$ 是点数。邻接表的适用性弥补了邻接矩阵的空间复杂度问题,使得算法的总体表现更优秀。