📜  门| GATE CS Mock 2018年|问题22(1)

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

门 | GATE CS Mock 2018年 | 问题22

本题为GATE CS Mock 2018年的第22题。这是一道关于图论知识的题目,要求求出给定图中所有最短路径的数量。

问题描述

给定一个有n个节点和m条边的有向无环图(DAG),每条边上都有一个权值,可能为负数,且权值可能相同。对于每对节点u和v,我们定义"最短路径"为u到v的所有路径中权值和最小的那一条路径。看到最短路径我们自然会想到迪杰斯特拉算法或者贝尔曼-福德算法。但是这些算法在面对负权边的情况时会失效,所以本题需要我们使用拓扑排序和动态规划来解决这个问题。

思路分析

对于这道题目,我们需要使用拓扑排序和动态规划来解决。我们先对DAG进行拓扑排序,从拓扑排序的最后一个节点开始,计算它到DAG中所有节点的最短路径数。具体做法如下所示:

  1. 对DAG进行拓扑排序,得到排好序的节点。
  2. 初始化一个长度为n的数组shortest[],用来保存节点i到节点n的最短路径数,shortest[i]的初始值为0。
  3. 从最后一个节点n开始,设置shortest[n]的值为1。
  4. 遍历排好序的节点列表,对每个节点i进行如下操作:
    • 对i的所有后继节点j,如果从i到j的距离比从i到n的距离短,则将shortest[i]的值加上shortest[j]的值。
    • 完成上一步操作后,将shortest[i]的值存储到数组中。
  5. 最终shortest[1]的值就是从节点1到节点n的最短路径数。

上述算法的时间复杂度为O(m+n),其中m为边的数量,n为节点的数量。

代码实现

下面是使用Python实现的代码,需要按照Markdown格式返回。其中,dist数组用来记录i到n的最短路径长度,count数组用来记录i到n的最短路径数。

# Python代码
def shortest_paths_count(n, edges):
    adj_list = [[] for _ in range(n + 1)]
    for u, v, w in edges:
        adj_list[u].append((v, w))
    dist = [float('inf') for _ in range(n + 1)]
    count = [0 for _ in range(n + 1)]
    dist[n] = 0
    count[n] = 1
    topo_sorted = topological_sort(n, adj_list)
    for u in topo_sorted:
        for v, w in adj_list[u]:
            if dist[u] > dist[v] + w:
                dist[u] = dist[v] + w
                count[u] = count[v]
            elif dist[u] == dist[v] + w:
                count[u] += count[v]
    return count[1]
        
def topological_sort(n, adj_list):
    in_degree = [0 for _ in range(n + 1)]
    for v in range(1, n + 1):
        for u, _ in adj_list[v]:
            in_degree[u] += 1
    sources = [v for v in range(1, n + 1) if in_degree[v] == 0]
    topo_sorted = []
    while sources:
        u = sources.pop()
        topo_sorted.append(u)
        for v, _ in adj_list[u]:
            in_degree[v] -= 1
            if in_degree[v] == 0:
                sources.append(v)
    return topo_sorted

我们可以使用以下样例来测试上述代码。

样例测试
# Python代码
n = 5
edges = [(1, 2, 1), (2, 3, 3), (3, 4, 1), (4, 5, 2), (1, 3, 2), (2, 4, 2), (3, 5, 4)]
assert shortest_paths_count(n, edges) == 3

n = 2
edges = [(1, 2, 0)]
assert shortest_paths_count(n, edges) == 1

n = 3
edges = [(1, 2, 1), (2, 3, 2), (1, 3, 2)]
assert shortest_paths_count(n, edges) == 2

以上是本题的完整代码实现及样例测试。