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;
}