📜  门| GATE-CS-2006 |问题8(1)

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

问题描述

给定一个有向无环图,每个节点都有一个权重值。现在,我们要找到一条路径使得路径的总权值最大化,并且这条路径上所有的节点都满足以下条件:

  1. 该节点的入度为1,即只有一个节点指向该节点;
  2. 该节点的出度为1,即只有该节点指向一个节点。

输出这条路径的最大权值和。

例如,在下面这个图中,从节点1到节点5的路径上的所有节点都满足条件1和条件2,路径的最大权值和是24。

有向无环图

解题思路

本题是一道典型的动态规划问题。我们按照拓扑排序的顺序遍历有向无环图中的每个节点,对于每个节点,我们记录到达该节点的最大权值,即该节点的权值加上前驱节点的最大权值。具体而言,设$w_i$表示节点$i$的权值,$last_j$表示节点$j$的前驱节点,$dp_i$表示到达节点$i$的最大权值,则有:

$$dp_i = w_i + dp_{last_i}$$

对于入度为0的节点(即没有前驱节点的节点),将其最大权值设为其权值本身。对于出度为0的节点(即没有后继节点的节点),将其最大权值设为0。最终,在所有到达终止节点的路径中,找到最大的路径权值,即为所求的答案。

时间复杂度为$O(n)$,其中$n$为节点数目。

代码实现
def max_weight_path(graph):
    n = len(graph) # 图中节点数
    dp = [0] * n # 记录到达每个节点的最大权值
    # 拓扑排序
    node_order = [] 
    in_degree = [0] * n # 记录所有节点的入度
    for i in range(n):
        for v in graph[i]:
            in_degree[v] += 1
    queue = [i for i in range(n) if in_degree[i] == 0]
    while queue:
        node = queue.pop(0)
        node_order.append(node)
        for v in graph[node]:
            in_degree[v] -= 1
            if in_degree[v] == 0:
                queue.append(v)
    # 按拓扑序遍历每个节点,更新最大权值
    for node in node_order:
        max_weight = 0
        for last_node in graph[node]:
            max_weight = max(max_weight, dp[last_node])
        dp[node] = max_weight + (w[node] if in_degree[node] != 0 else 0)
    # 找到所有到达终止节点的路径中的最大权值
    max_path_weight = max([dp[i] for i in range(n) if len(graph[i]) == 0])
    return max_path_weight

注:以上代码中,graph为输入的图,是一个邻接表表示。其中w[i]表示节点$i$的权值,为全局变量。