📅  最后修改于: 2023-12-03 15:12:36.385000             🧑  作者: Mango
本题是 GATE CS 2013 年考题的第 25 题。
给定一个有向无环图(DAG),其中每个节点都有权值,找到一个路径,使得路径起点为图中的某个节点,路径的下一个节点(如果存在)比起点节点的权值高,路径的长度最长。写一个高效的算法实现此功能。
输入参数是一个有向无环图 graph
,一个结构体数组 vertex
, vertex[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。
我们定义一个数组 dp
,dp[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
数组中的最大值就是题目要求的答案。