📅  最后修改于: 2023-12-03 14:58:20.810000             🧑  作者: Mango
本文将向程序员介绍 Gate CS 2019 年度的问题 6,该问题主要涉及动态规划与贪心算法的应用。该问题所涉及的算法是求解从一个有 n 个顶点的有向无环图中选择最大权值路径的问题,其中顶点 u 的权值是 w[u],一条边的权值是这条边头顶点的权值。
给定一个有向无环图,每个顶点上存在一个权值。要求选出一些顶点,满足从起始点到这些点路径上的点权值之和最大,同时任意两点间都不存在边。
该问题可以通过动态规划和贪心算法来解决。
假设 dp[u] 表示以 u 为终点的最大权值路径,那么 dp[u] 可以这样推导出:
dp[u] = max(dp[v] + w[u])
其中 v 是 u 的前继节点,w[u] 是点 u 的点权。但是我们并不知道 v 是谁,这里需要对 u 的入度为 0 的节点求解 dp 值。可以使用拓扑排序来对该问题进行求解。
func longestPathDAG(w []int, graph [][]int) int {
n := len(w)
topsort := topsort(graph, n)
res := 0
dp := make([]int, n)
for i := range topsort {
u := topsort[i]
for _, v := range graph[u] {
dp[v] = max(dp[v], dp[u]+w[u])
}
res = max(res, dp[u])
}
return res
}
由于该问题是 DAG,所以该问题可以使用贪心算法求解。每次选取入度为 0 的点中权值最大的点进行贪心。由于从入度为 0 的点出发都会到达终点,所以可以不断地从入度为 0 的点中取到一个点,记录这个点的权值,然后将这个点的所有出边从图中删除,直到所有的点都被删除。
func longestPathDAG(w []int, graph [][]int) int {
n := len(w)
visited := make([]bool, n)
indegrees := make([]int, n)
for i := 0; i < n; i++ {
for _, v := range graph[i] {
indegrees[v]++
}
}
q, res := make([]int, 0), 0
for i := 0; i < n; i++ {
if indegrees[i] == 0 {
q = append(q, i)
}
}
for len(q) > 0 {
u := q[0]
q = q[1:]
visited[u] = true
res = max(res, w[u])
for _, v := range graph[u] {
if !visited[v] {
indegrees[v]--
if indegrees[v] == 0 {
q = append(q, v)
}
w[v] = max(w[v], w[u]+w[v])
}
}
}
return res
}
对于动态规划算法,使用拓扑排序对 DAG 进行排序,时间复杂度为 O(V+E),其中 V 表示顶点数,E 表示边数。如果采用堆优化,时间复杂度可以优化至 O(E log V),但是在实际计算中,两种算法的耗时并不会相差很多。
对于贪心算法,对于每个节点都必须累加一次,时间复杂度为 O(V+E)。
本文向程序员介绍了 Gate CS 2019 年度的问题 6,这个问题主要涉及动态规划和贪心算法的应用。其中动态规划的时间复杂度为 O(V+E),贪心算法的时间复杂度也为 O(V+E)。对于实际应用中的情况,根据具体的情况选择合适的算法能够更快地求解问题,提高程序的效率。