📜  门| GATE CS 2019 |简体中文第44章(1)

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

GATE CS 2019 简体中文第44章

本文是GATE CS 2019考试中的一道题目,主题是“路由算法”。

背景

路由算法是指在计算机网络中确定数据包转发路径的一类算法。在路由算法中,最短路径算法是一种常见的算法,它可以找到两个节点之间的最短路径。

题目描述

考虑一个具有5个节点的无向网络。节点的编号从A到E。图形表示如下:

A----B
|\  /|\
| \/ | \
| /\ |  \
|/  \|   C
D----E

给定以下有关节点之间距离的信息表:

| --- | A | B | C | D | E | | --- | --- | --- | --- | --- | --- | | A | - | 10 | 5 | 999 | 999 | | B | 10 | - | 3 | 1 | 999 | | C | 5 | 3 | - | 9 | 2 | | D | 999 | 1 | 9 | - | 7 | | E | 999 | 999 | 2 | 7 | - |

其中,999表示节点之间无法直接到达。

使用Dijkstra算法求出节点A到其他节点的最短距离。

解答

Dijkstra算法是一种常见的最短路径算法,它使用了贪心策略,每次选择未访问的节点中距离源节点最近的节点,并更新源节点到所有邻居节点之间的距离。

下面是算法的伪代码:

1 function Dijkstra(Graph, source):
2
3     create vertex set Q
4
5     for each vertex v in Graph:             // 初始化
6         dist[v] ← INFINITY                  // 除源点外,其余顶点距离设为无穷大
7         prev[v] ← UNDEFINED                 // 每个顶点的前驱节点都未知
8         add v to Q                          // 将所有顶点添加到集合Q中
9
10     dist[source] ← 0                        // 初始化源点的距离为0
11
12     while Q is not empty:
13         u ← vertex in Q with min dist[u]   // 选取离源点最近的顶点
14         remove u from Q
15         
16         for each neighbor v of u:           // 对u的每个邻居v,更新v的距离
17             alt ← dist[u] + length(u, v) 
18             if alt < dist[v]:               // 如果新的距离更小
19                 dist[v] ← alt              // 更新距离
20                 prev[v] ← u                // 更新前驱节点
21         
22     return dist, prev

其中,Graph是指网络的邻接表表示,source是指起始节点。

下面是使用Dijkstra算法求解最短路径的过程:

  1. 初始化节点A到其他节点的距离和前驱节点。
    dist = {'A': 0, 'B': 10, 'C': 5, 'D': 999, 'E': 999}
    prev = {'A': None, 'B': 'A', 'C': 'A', 'D': None, 'E': None}
    
  2. 选取离源点最近的顶点A,计算到达其邻居B和C的距离。发现到B的距离更短,更新B的距离和前驱节点。
    dist = {'A': 0, 'B': 10, 'C': 5, 'D': 1004, 'E': 1004}
    prev = {'A': None, 'B': 'A', 'C': 'A', 'D': None, 'E': None}
    
  3. 选取离源点最近的节点C,计算到达其邻居B和E的距离。发现到E的距离更短,更新E的距离和前驱节点。
    dist = {'A': 0, 'B': 8, 'C': 5, 'D': 1004, 'E': 7}
    prev = {'A': None, 'B': 'C', 'C': 'A', 'D': None, 'E': 'C'}
    
  4. 选取离源点最近的节点B,计算到达其邻居C和D的距离。发现到C的距离更短,更新C的距离和前驱节点。
    dist = {'A': 0, 'B': 8, 'C': 5, 'D': 11, 'E': 7}
    prev = {'A': None, 'B': 'C', 'C': 'A', 'D': 'B', 'E': 'C'}
    
  5. 选取离源点最近的节点E,计算到达其邻居C和D的距离。发现到C的距离更短,但已经更新过C,不需要再次更新。
  6. 选取离源点最近的节点D,计算到达其邻居B和E的距离。发现到E的距离更短,但已经更新过E,不需要再次更新。
  7. 算法结束,返回最短距离和前驱节点。
    dist = {'A': 0, 'B': 8, 'C': 5, 'D': 11, 'E': 7}
    prev = {'A': None, 'B': 'C', 'C': 'A', 'D': 'B', 'E': 'C'}
    

最终,节点A到其他节点的最短距离为:

  • A -> B: 8
  • A -> C: 5
  • A -> D: 11
  • A -> E: 7
代码片段

下面是Python代码实现Dijkstra算法:

def dijkstra(graph, source):
    dist = {node: float('inf') for node in graph}  # 到每个节点的距离
    prev = {node: None for node in graph}          # 前驱节点
    dist[source] = 0                               # 起始节点距离为0
    
    unvisited = graph.copy()                       # 未访问节点
    
    while unvisited:
        curr_node = min(unvisited, key=dist.get)    # 距离源节点最近的节点
        unvisited.remove(curr_node)                 # 移除节点
        
        for neighbor, weight in graph[curr_node].items():
            alt = dist[curr_node] + weight           # 计算到该邻居的距离
            if alt < dist[neighbor]:                 # 发现更短距离,更新
                dist[neighbor] = alt
                prev[neighbor] = curr_node
                
    return dist, prev

其中,graph是指邻接表表示的网络,source是指起始节点。

下面是对本题使用Dijkstra算法求解的Python代码:

graph = {
    'A': {'B': 10, 'C': 5},
    'B': {'A': 10, 'C': 3, 'D': 1},
    'C': {'A': 5, 'B': 3, 'E': 2, 'D': 9},
    'D': {'B': 1, 'C': 9, 'E': 7},
    'E': {'C': 2, 'D': 7}
}

dist, prev = dijkstra(graph, 'A')
print(dist)  # {'A': 0, 'B': 8, 'C': 5, 'D': 11, 'E': 7}