首页 > 其他 > 详细

[CTSC1997] 选课 树上背包

时间:2020-10-23 20:45:28      阅读:25      评论:0      收藏:0      [点我收藏+]

[CTSC1997] 选课 树上背包

题意

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

\[1\leq n\leq 300\1\leq m\leq 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];
}

[CTSC1997] 选课 树上背包

原文:https://www.cnblogs.com/hznumqf/p/13865745.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!