📅  最后修改于: 2023-12-03 15:28:43.157000             🧑  作者: Mango
这是 Gate-CS-2007 的第 76 题,题目描述如下:
给定一个外向拓扑图(directed acyclic graph,DAG),请你写一个程序来找到最长路(longest path)的长度。其中,最长路定义为起始节点到结束节点经过的路径中,每个节点之间权重和的最大值。
最长路径问题可以用动态规划来解决。根据定义,最长路需要满足以下条件:
定义 $DP[i]$ 为从起始节点到第 $i$ 个节点的最大权重和,则有以下递推关系式:
$DP[i] = \max\limits_{j \in in(i)} (DP[j] + w(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
最长路径问题是一个经典且实用的问题,解决它可以使用动态规划和拓扑排序。在实现时,需要注意记录每个节点的前驱节点以便还原路径。