📜  门| GATE-CS-2007 |第 76 题(1)

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

题目介绍

这是 Gate-CS-2007 的第 76 题,题目描述如下:

给定一个外向拓扑图(directed acyclic graph,DAG),请你写一个程序来找到最长路(longest path)的长度。其中,最长路定义为起始节点到结束节点经过的路径中,每个节点之间权重和的最大值。

解题思路

动态规划

最长路径问题可以用动态规划来解决。根据定义,最长路需要满足以下条件:

  • 路径中的每个节点必须是 DAG 中顺序排列的。
  • 路径的权重和必须最大。

定义 $DP[i]$ 为从起始节点到第 $i$ 个节点的最大权重和,则有以下递推关系式:

$DP[i] = \max\limits_{j \in in(i)} (DP[j] + w(j,i))$

其中,

  • $in(i)$ 表示所有指向节点 $i$ 的节点的集合;
  • $w(j,i)$ 表示节点 $j$ 到节点 $i$ 的边的权重。

最终结果为 $DP[m]$,其中 $m$ 是 DAG 的结束节点。

拓扑排序

动态规划的递推关系式需要用到入度的概念,即每个节点有多少个节点指向它。因此,我们可以先用拓扑排序来将 DAG 中的节点排成一条线性序列。这个序列需要满足 DAG 的定义,即每个节点都必须在它前面的节点的入度为 0。

实现细节

具体实现时,我们可以先用拓扑排序将 DAG 排成线性序列,然后根据递推关系式计算每个节点的最长路径。在计算过程中,可以记录每个节点的前驱节点,以便还原路径。最后,我们可以从结束节点 $m$ 开始遍历前驱节点还原路径,并输出路径上的权重和即可。

代码实现

下面是使用 Python 实现的代码片段:

def longest_path(dag, start, end):
    # 拓扑排序,得到 DAG 中每个节点的入度和序列
    in_degrees = [0] * len(dag)
    for _, to in dag:
        in_degrees[to] += 1
    topo_order = [i for i in range(len(dag)) if in_degrees[i] == 0]

    # 计算每个节点的最长路径和前驱节点
    dp = [float('-inf')] * len(dag)
    dp[start] = 0
    pre = [None] * len(dag)
    for i in topo_order:
        for frm, to, weight in dag:
            if to == i:  # i 是当前节点
                if dp[frm] + weight > dp[to]:  # 更新最长路径和前驱节点
                    dp[to] = dp[frm] + weight
                    pre[to] = frm

    # 还原路径并输出
    path, node = [], end
    while node is not None:
        path.append(node)
        node = pre[node]
    path.reverse()
    return dp[end], path

总结

最长路径问题是一个经典且实用的问题,解决它可以使用动态规划和拓扑排序。在实现时,需要注意记录每个节点的前驱节点以便还原路径。