zoukankan      html  css  js  c++  java
  • 洛谷 P2014 选课(树形背包)

    洛谷 P2014 选课(树形背包)

    思路

    题面:洛谷 P2014

    如题这种有依赖性的任务可以用一棵树表示,因为一个儿子要访问到就必须先访问到父亲。然后,本来本题所有树是森林(没有共同祖先),但是题中的节点(0)其实就可以当做一个LCA,从节点(0)开始dp。

    状态定义:(dp[x][m])x节点,选则m课,获得的最大学分

    决策时,类比背包,遍历每一个状态,用儿子的状态更新

    dp转移方程(已优化一维):

    [dp[x][i] = max{dp[x][i-j]+dp[son(x)][j]} ]

    这里需要注意的是,你定义的dp状态,是当前节点共选(m)课,而节点(0)是必须要选到的,所以应该一个选取(m+1)个课程,并且最终状态不是(dp[0][m])而是(dp[0][m+1])(卡了我好久……,所以定义dp状态时一定要自己清楚所代表的含义)

    此题非常像洛谷 P1273 有线电视网,都是树形dp

    代码

    #include <cstdio>
    #include <vector>
    #define MAXN 303
    #define INF 0x3fffffff
    #define MAX(A,B) ((A)>(B)?(A):(B))
    #define MIN(A,B) ((A)<(B)?(A):(B))
    using namespace std;
    int n,m,dp[MAXN][MAXN];
    vector <int> mp[MAXN];
    int dfs(int x){
        int cnt=1;
        for(register int i=0;i<mp[x].size();++i){
            int v=mp[x][i];
            int sz=dfs(v);
            cnt+=sz;
            for(register int j=m+1;j>=2;--j)
                for(register int k=0;k<=MIN(j-1, sz);++k)
                    dp[x][j]=MAX(dp[x][j-k]+dp[v][k], dp[x][j]);
        }
        return cnt;
    }
    int main(){
        scanf("%d %d", &n, &m);
        for(register int i=1;i<=n;++i){
            int k,s;
            scanf("%d %d", &k, &s);
            dp[i][1]=s;
            mp[k].push_back(i);
        }
        dfs(0);
        printf("%d", dp[0][m+1]);
        return 0;
    }
    
  • 相关阅读:
    14.Java基础_函数/函数重载/参数传递
    98. 验证二叉搜索树(深搜)
    13.Java基础_数组内存图
    12Java基础_数组定义格式/动态初始化/静态初始化
    计算几何基础
    11.Java基础_IDEA常用快捷键
    Add Two Numbers
    Two Sum
    登录界面id属性的使用
    系统查看
  • 原文地址:https://www.cnblogs.com/santiego/p/10516115.html
Copyright © 2011-2022 走看看