zoukankan      html  css  js  c++  java
  • 洛谷P2014 选课 题解 树形DP

    题目链接:https://www.luogu.com.cn/problem/P2014

    题目大意:

    大学里有 (n) 门课,这些课之间有依赖关系(先修课)。每门课有学分 (s[i]) ,求选择 (m) 课最多能获得的学分?

    解题思路:

    树形DP。

    我们可以假设先修课和当前这节课之间是父子关系(当前课是儿子,先修课是父亲),然后没有先修课的节点的父节点为 (0) 号节点,这样就构成了一棵以 (0) 为根节点的树。

    然后定义状态 (f[u][i]) 表示以 (u) 为根节点的子树中选择了 (i) 门课的最大学分。
    其实这个状态的具体含义是:

    (u) 为根节点,(并且此时遍历到了它的子节点 (v)),到子节点 (v) 为止(也就是从第 (1) 个儿子到子节点 (v))选了 (i) 门课的最大学分。

    (f[u][i] = max(f[u][i-j] + f[v][j]))

    这其中蕴含着一定的 背包 思想。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 330;
    int n, m, p, s[maxn], f[maxn][maxn], size[maxn];
    vector<int> g[maxn];
    void dfs(int u) {
        f[u][1] = s[u];
        size[u] = 1;
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            dfs(v);
            size[u] += size[v];
        }
        for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
            int v = *it;
            for (int i = size[u]; i >= 2; i --) {
                for (int j = 0; j <= size[v] && j < i; j ++) {
                    f[u][i] = max(f[u][i], f[u][i-j] + f[v][j]);
                }
            }
        }
    }
    int main() {
        cin >> n >> m;
        if (m > n) m = n;
        for (int i = 1; i <= n; i ++) {
            cin >> p >> s[i];
            g[p].push_back(i);
        }
        dfs(0);
        cout << f[0][m+1] << endl;
        return 0;
    }
    
  • 相关阅读:
    Python 产生和验证IMEI Vevi
    Ubuntu常见问题及解决方案
    error LNK2019: 无法解析的外部符号 WinMain(vs2019)
    NVIDIA GPU 架构演进
    RFCN详解
    Visdom 使用教程
    传统特征提取方法总结
    模型转换、模型压缩、模型加速工具
    YoloV5实战
    React vscode 创建 react 项目流程
  • 原文地址:https://www.cnblogs.com/quanjun/p/12253966.html
Copyright © 2011-2022 走看看