📜  门| GATE CS 2019 |问题 6(1)

📅  最后修改于: 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)。对于实际应用中的情况,根据具体的情况选择合适的算法能够更快地求解问题,提高程序的效率。