zoukankan      html  css  js  c++  java
  • [CTSC1997] 选课 树上背包

    [CTSC1997] 选课 树上背包

    题意

    选择一些课程,每个课程有一个唯一的先修课程,每个课程有一个学分,今有一名学生需要从中选择(m)门课程,问能够获得的最大学分是多少,每门课程的选择前提是选择先修课程

    [1leq nleq 300\ 1leq mleq 300 \ k_i和s_i表示第i门课程的先修课程,s_i表示第i门课的学分 ]

    分析

    每个点有唯一的前驱,因此可以转化为树上问题

    (dp[i][j])表示第(i)个结点选择了(j)个子孙结点能够取到的最大学分,这就把问题转化成了树上背包问题

    [dp[i][j] = max(dp[i][j - k + 1] + dp[v][k]) ]

    根据这个方程,在树上DFS一遍就可以了

    注意细节,因为第二维不算自己,所以要注意+1-1

    当然这里还有细节,刷新的时候要从大到小枚举,否则会影响后面的答案

    代码

    vector<int> e[505];
    int dp[505][505];
    int w[505];
    
    int dfs(int u) {
        if (!e[u].size()) return 0;
        int siz = 0;
        for (auto v : e[u]) {
            int t = dfs(v);
            siz += t + 1;
            for (int j = siz; j >= 0; j--)
                for (int k = 0; k <= min(t,j - 1); k++)
                    dp[u][j] = max(dp[u][j], dp[u][j - k - 1] + dp[v][k]);
        }
        return siz; 
    }
    
    int main() {
        int n = readint();
        int m = readint();
        for (int i = 1; i <= n; i++) {
            int x = readint();
            int y = readint();
            if (!x)  e[0].push_back(i);
            else e[x].push_back(i);
            w[i] = y;
        }
        for (int i = 1; i <= n; i++)
            dp[i][0] = w[i];
        dfs(0);
        cout << dp[0][m];
    }
    
  • 相关阅读:
    [LeetCode]Add Two Numbers
    [LeetCode]Longest SubString Without Repeating Characters
    [LeetCode]Median of Two Sorted Arrays
    [LeetCode]Two Sum
    动态规划
    [shell编程]一个简单的脚本
    一些linux的问题
    核稀疏表示分类(KSRC)
    conda 按照指定源下载python包
    python 保留两位小数
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13865745.html
Copyright © 2011-2022 走看看