• 洛谷P2014 选课(树形DP+分组背包)


    题目描述

    在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有 NNN 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择 MMM 门课程学习,问他能获得的最大学分是多少?

    输入格式

    第一行有两个整数 NNN , MMM 用空格隔开。( 1≤N≤3001 leq N leq 3001N300 , 1≤M≤3001 leq M leq 3001M300 )

    接下来的 NNN 行,第 I+1I+1I+1 行包含两个整数 kik_i kisis_isi, kik_iki 表示第I门课的直接先修课,sis_isi 表示第I门课的学分。若 ki=0k_i=0ki=0 表示没有直接先修课(1≤ki≤N1 leq {k_i} leq N1kiN , 1≤si≤201 leq {s_i} leq 201si20)。

    输出格式

    只有一行,选 MMM 门课程的最大得分。

    输入输出样例

    输入 #1
    7  4
    2  2
    0  1
    0  4
    2  1
    7  1
    7  6
    2  2
    
    输出 #1
    13
    #include <bits/stdc++.h>
    using namespace std;
    int n,m;
    vector<int> v[305];//v[i]存储i的儿子节点 
    int dp[305][305]={0};//dp[i][j]表示从i为根的子树里选j门课所取得的最大分数 
    int score[305];//第i门课的分数为score[i] 
    void dfs(int x)
    {
        dp[x][0]=0;//显然啥课都不选 dp值为0 
        int i;
        for(i=0;i<v[x].size();i++)//枚举x的每个子节点 
        {
            int y=v[x][i];//y是子节点 
            dfs(y);//先dfs处理了子树 这样后面才能转移 
            int t,k;
            for(t=m;t>=0;t--)//背包容量 
            {
                for(k=0;k<=t;k++)//“在子节点中选k门课”构成一个物品 这里正序倒序都能ac 
                {
                    if(t>=k)dp[x][t]=max(dp[x][t],dp[x][t-k]+dp[y][k]);//进行转移 选/不选取最大 
                }
            }
        }
        if(x!=0)//x不是虚拟节点的话 
        {
            int t;
            for(t=m;t>0;t--)//t不能取0 
            {
                dp[x][t]=dp[x][t-1]+score[x];//必然要加上老大 因为x是它子节点的先修课 所以t里面一定包含x这门课 
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        int i;
        for(i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==0)
            {
                v[0].push_back(i);
            }
            else v[x].push_back(i);
            score[i]=y;
        }
        dfs(0);//从虚拟节点开始处理 
        cout<<dp[0][m];//从0的子树里选m个课程 虚拟节点自然被忽略了 
        return 0;
    }

    注意虚拟零节点的使用以及分组背包的条件,物品泛化等。

  • 相关阅读:
    js动态添加CSS
    LINUX命令行回滚SVN版本
    LINUX文件名批量修改
    LINUX下文件编码转换 iconv
    ubuntu下eclipse的svn插件使用javahl
    HTML5学习笔记 本地数据库
    正则表达式
    我的第一篇博客
    【分布式锁的演化】分布式锁居然还能用MySQL?
    【分布式锁的演化】终章!手撸ZK分布式锁!
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12551288.html
Copyright © 2020-2023  润新知