P2014 [CTSC1997] 选课

P2014 [CTSC1997] 选课

树形DP,题目说了每门课有一门或没有直接先修课,所以不存在环,也就是个森林,我们可以利用题目的性质,用 \(0\) 号节点把森林连起来,选择数 \(m\) 自加即可。

DP式是很普通的树形背包,设 \(f[i][j]\) 表示到 \(i\) 节点选择 \(j\) 门课的最大价值。

\[f[u][j]=max \{ f[v][k]+f[u][j-k]\} \]

啥意思?就是当前枚举的子节点 \(v\)\(k\) 个时,限制的当前节点选的数量是 \(j\) ,那么需要加上除 \(v\) 节点之外子节点的最大贡献,而这些节点能选的数量是 \(j-k\) 个。

注意这是个 \(01\) 背包,倒序枚举。

/*
Knowledge : Rubbish Algorithm
Work by :Gym_nastics
Time : O(AC)
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
const int N=1e3+6;

int read() {
    int x=0,f=0;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15);
    return f?-x:x;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+48);
}

int f[N][N],n,m,head[N],cnt;struct node{int v,nxt;}e[N];
void Add_edge(int u,int v){e[++cnt]=(node){v,head[u]};head[u]=cnt;}

void dfs(int u){
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].v;dfs(v);
        for(int j=m;j>=1;j--)for(int k=0;k<j;k++)
        f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
    }
}

signed main(int argc,char **argv) {
   memset(head,-1,sizeof head);
   n=read();m=read()+1;
   for(int i=1;i<=n;i++){
       int x=read();f[i][1]=read();
       Add_edge(x,i);
   }dfs(0);print(f[0][m]);
   return 0;
}

posted @ 2022-03-20 16:23  Gym_nastics  阅读(66)  评论(0编辑  收藏  举报