📜  门| GATE CS 2013 |问题25(1)

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

门 | GATE CS 2013 | 问题25

本题是 GATE CS 2013 年考题的第 25 题。

题目描述

给定一个有向无环图(DAG),其中每个节点都有权值,找到一个路径,使得路径起点为图中的某个节点,路径的下一个节点(如果存在)比起点节点的权值高,路径的长度最长。写一个高效的算法实现此功能。

输入格式

输入参数是一个有向无环图 graph,一个结构体数组 vertexvertex[i] 表示第 i 个节点的属性。结构体 vertex 的定义如下:

struct Vertex {
    int id;
    int weight;
};

其中,id 表示节点的编号,weight 表示节点的权值。

graph 使用邻接矩阵表示,graph[i][j] 表示节点 i 和节点 j 之间是否存在有向边。如果存在连接,graph[i][j] 的值为 1,否则为 0。

注意,graph 是一个方阵,graph[i][i] 的值为 0。

输出格式

输出一个整数,表示满足条件的最长路径的长度。

示例

输入:

vector<vector<int>> graph = {
  {0, 1, 1, 0},
  {0, 0, 1, 1},
  {0, 0, 0, 1},
  {0, 0, 0, 0},
};

vector<Vertex> vertex = {
  {0, 2},
  {1, 5},
  {2, 7},
  {3, 4},
};

输出:

3

解释:

图示如下:

2 -> 3
 \   ^
  v  /
  1 <- 0

最长路径为 2 -> 1 -> 0。

算法思路

本题要求一条路径,使得路径上节点的权值递增,长度最长。由于 DAG 中不存在环,因此可以使用拓扑排序来遍历 DAG。

我们定义一个数组 dpdp[i] 表示以节点 i 为起点的从 i 开始的最长路径长度。初始时,dp[i] 的值为对应节点的权值。

对于每一个节点 i,我们从它的所有后继节点 j 中选取一个 dp[j] 最大的节点,更新 dp[i] 的值,即:

dp[i] = max(dp[j] + vertex[i].weight)

需要注意的是,如果节点 i 没有后继节点,那么这个 max 的值是 vertex[i].weight

最终,dp 数组中的最大值就是题目要求的答案。

代码实现
int longest_path(vector<vector<int>> graph, vector<Vertex> vertex) {
    int n = graph.size();
    vector<int> in_degree(n), dp(n);

    // 计算每个节点的入度
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (graph[j][i]) {
                in_degree[i]++;
            }
        }
    }

    // 拓扑排序
    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (in_degree[i] == 0) {
            dp[i] = vertex[i].weight;
            q.push(i);
        }
    }
    while (!q.empty()) {
        int cur = q.front(); q.pop();
        for (int i = 0; i < n; i++) {
            if (graph[cur][i]) {
                dp[i] = max(dp[i], dp[cur] + vertex[i].weight);
                if (--in_degree[i] == 0) {
                    q.push(i);
                }
            }
        }
    }

    // 找到最长的路径
    int max_len = 0;
    for (int i = 0; i < n; i++) {
        max_len = max(max_len, dp[i]);
    }

    return max_len;
}

其中,in_degree[i] 表示节点 i 的入度,dp[i] 表示以节点 i 为起点的最长路径长度。在拓扑排序中,对于每一个节点 i,我们从它的所有后继节点 j 中选取一个 dp[j] 最大的节点,更新 dp[i] 的值。

最终,dp 数组中的最大值就是题目要求的答案。