• P2014 选课 (树形动规)


    题目描述

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

    输入输出格式

    输入格式:

    第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=300)

    接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。

    输出格式:

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

    输入输出样例

    输入样例#1: 
    7  4
    2  2
    0  1
    0  4
    2  1
    7  1
    7  6
    2  2
    
    输出样例#1: 
    13
     

    Solution

    这个题算是树上背包入门题了.

    很简单的DP思路.

    状态定义:

    f[ i ] [ j ] 表示当前 i 这个节点,已经选了 j 个的最大价值

    状态转移:

    for ( j=m ; j--> 1;j-- )

    for ( k=1 ; k<=m; k++ )

    f [ now ] [ j ] = max ( f[ now ][ j ], f[ now ][ j-k ]+f[ to ][ k ]);

    类似于01背包的转移方程,只是把它放到了树上而已.

    然后我进行了一个预处理,预先将每个节点的子树节点个数记录起来,然后在转移的时候就只要转移 min (num[now],m );

    优化到了 0ms.

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=305;
    
    struct sj{
        int to;
        int next;
    }a[maxn];
    int c[maxn],v[maxn],ans;
    int size,head[maxn],n,m;
    int f[maxn][maxn],num[maxn];
    
    void add(int x,int y)
    {
        a[++size].to=y;
        a[size].next=head[x];
        head[x]=size;
    }
    
    void pre(int x)
    {
        num[x]=1;
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            if(!num[tt])
            {
                pre(tt);
                num[x]+=num[tt];    
            }
        }
        f[x][1]=c[x];
        return;
    }
    
    void dfs(int x)
    {
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            dfs(tt);
            int jj=min(m,num[x]);
            for(int j=jj;j>=1;j--)
            for(int k=1;k<j;k++)
            f[x][j]=max(f[x][j],f[tt][k]+f[x][j-k]);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            c[i]=y; add(x,i);
        }
        m++;
        //此处因为 0 对于答案不算体积.
        pre(0);
        dfs(0);
        cout<<f[0][m]<<endl;
        return 0;
    }
  • 相关阅读:
    【NodeJs】Nodejs系列安装
    【webstrom+stylus】stylus在webstrom中的识别
    python基础:数据类型一
    python基础:流程控制案例:
    python基础:if判断与流程控制案例
    计算机基础与python入门
    Robot Framework-断言函数
    RF设置全局变量
    RF自定义系统关键字
    RF第二讲--Selenium2Library库的简单实用
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9069531.html
Copyright © 2020-2023  润新知