• P2014 [CTSC1997]选课(树上背包)


    题目描述

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

    输入格式

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

    接下来的 NN 行,第 I+1I+1 行包含两个整数 k_iki和 s_isik_iki 表示第I门课的直接先修课,s_isi 表示第I门课的学分。若 k_i=0ki=0 表示没有直接先修课(1 leq {k_i} leq N1kiN , 1 leq {s_i} leq 201si20)。

    输出格式

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

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=305;
    int n,m;
    vector<int> g[maxn];
    int size[maxn];
    int a[maxn];
    int dp[maxn][maxn];//表示在以i为根节点的子树里选择j门棵的最优解
    void dfs1 (int u) {
        size[u]=1;
        for (int v:g[u]) {
            dfs1(v);
            size[u]+=size[v];
        } 
    } 
    void dfs2 (int u) {
        for (int v:g[u]) {
            dfs2(v);
            for (int i=size[u];i>=0;i--)
                for (int j=size[v];j>=0;j--)
                    if (i>=j+1)
                        dp[u][i]=max(dp[u][i],dp[u][i-j-1]+dp[v][j]+a[v]);
        }
    }
    int main () {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(i);
            a[i]=y;
        }
        dfs1(0);
        dfs2(0);
        printf("%d
    ",dp[0][m]);
    }
  • 相关阅读:
    CentOS7安装Dnsmasq并更新最新版
    VMware vCenter Server Appliance(VCSA )6.7 部署,许可证破解
    vsphere6.7虚拟机与ESXI时间同步
    oracle使用存储过程返回数据集
    如何让CheckBoxList横着显示
    在oracle中创建自动增长字段
    oracle 11g安装客户端后使用ps/sql连接提示TNS适配器错误的解决办法
    myeclipse 网站项目部署失败
    Opera Dragonfly本地化
    ExtJs的fireEvent事件
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13503584.html
Copyright © 2020-2023  润新知