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

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

门 | GATE CS Mock 2018 | 问题 27

这是 Gate CS 模拟考试 2018 年的第 27 道题目,主要考察图论和动态规划。

题目描述

有一个包含 n 个节点的加权有向图,每个节点被标记为 12。我们要找到一条路径,使得此路径上的节点标记交替出现,即对于任意相邻的节点 uvu 被标记为 1v 被标记为 2,或者相反。

你需要返回满足这个条件的权重之和的最大值。

给定以下参数:

  • n: 表示节点的数量
  • m: 表示边的数量
  • a: 由三个整数组成的数组,表示有向图中的一条边。其中,a[i], a[i+1]a[i+2] 表示此图中一条边,从节点 a[i] 到节点 a[i+1],边权为 a[i+2]
  • L: 一个长度为 n 的数组,表示每个节点的标记。L[i]12
解题思路

此题需要用到两个算法:深度优先搜索(DFS)与动态规划(DP)。

  1. 深度优先搜索

首先,我们可以将有向图转化成一个无向图。对于每个节点 u,定义状态 f(u, i) 表示在节点 u 上、且最后一个节点的标记为 i 的最大路径权重。考虑从 u 开始的所有可能的情况:

  • 如果最后一个节点的标记是 1,则从 u 开始只能连接到标记为 2 的节点,此时有 f(u, 1) = w(u, v) + f(v, 2),其中 w(u, v) 表示边 (u, v) 的权重;
  • 同理,如果最后一个节点的标记是 2,则从 u 开始只能连接到标记为 1 的节点,此时有 f(u, 2) = w(u, v) + f(v, 1)

最终,答案即为从任意节点 u 开始、且最后一个节点标记为 12 的最大路径权重。

此处我们采用深度优先搜索的方式进行计算,时间复杂度为 $O(n)$。

  1. 动态规划

通过 DFS 的算法,我们可以得到每个节点最后一个节点标记为 12 的最大路径权重 f(u, 1)f(u, 2)。接着,我们采用动态规划的思想,得出任意两个节点之间的最大路径权重。

定义状态 dp(i, j) 表示从节点 i 出发,到节点 j 终止的最大路径权重。针对任意节点对 (i, j),考虑其中的一个节点的最后一个标记位 12 的情况,即:

  • 如果 i 的最后一个节点标记为 1,则 dp(i, j) = max(w(i, v) + f(v, 2) + dp(v, j)),其中 w(i, v) 表示从 iv 的边权;
  • 同理,如果 i 的最后一个节点标记为 2,则 dp(i, j) = max(w(i, v) + f(v, 1) + dp(v, j))

最终的答案即为所有从任意起点 i 出发到任意终点 j 终止的最大路径权重的最大值。

此处采用动态规划的方式进行计算,时间复杂度为 $O(n^2)$。

代码示例
def max_weight(n, m, a, L):
    graph = [[] for _ in range(n)]
    for i in range(0, len(a), 3):
        u, v, w = a[i]-1, a[i+1]-1, a[i+2]
        graph[u].append((v, w))
        graph[v].append((u, w))

    # 采用 DFS 计算最大路径权重
    f = [[-float('inf')] * 3 for _ in range(n)]  # f(u, i)
    visited = [False] * n

    def dfs(u):
        for v, w in graph[u]:
            if not visited[v]:
                visited[v] = True
                dfs(v)
                if L[u] == 1:
                    f[u][1] = max(f[u][1], w + f[v][2])
                    f[u][2] = max(f[u][2], w + f[v][1])
                else:
                    f[u][1] = max(f[u][1], w + f[v][1])
                    f[u][2] = max(f[u][2], w + f[v][2])

    for i in range(n):
        if not visited[i]:
            visited[i] = True
            f[i][1] = f[i][2] = 0
            dfs(i)

    # 采用 DP 计算任意节点对 (i, j) 之间的最大路径权重
    dp = [[-float('inf')] * n for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if i == j:
                dp[i][j] = 0
            elif L[i] == 1:
                for v, w in graph[i]:
                    dp[i][j] = max(dp[i][j], w + f[v][2] + dp[v][j])
            else:
                for v, w in graph[i]:
                    dp[i][j] = max(dp[i][j], w + f[v][1] + dp[v][j])

    return max([max(dp[i]) for i in range(n)])

这是 Python 3 的一个实现。如果你使用的是其他的语言,请根据上述思路进行相应的编程。