[codevs1378]选课
做这道题本来是想复习一下最基本的树形dp模型,结果没想到卡了大半天还调不出来
首先是把多叉树转化为二叉树
Ans(x,y):表示节点x取y门课的最高学分
Ans(x,y)=max(Ans(x.l,k-1)+x.v+f(x.r,y-k))k=0,1,..y
400表示空节点,0是根节点.
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<cmath>
5 using namespace std;
6 struct node{
7 int l,r,value;
8 }T[600]={0};
9 int n,m;
10 int Ans[600][600];
11 int f[350]={0};//记录是否有左孩子,若有则记录左孩子的编号
12 int read(){
13 char ch=getchar();
14 int x=0,f=1;
15 while (ch<'0'||ch>'9'){
16 if (ch=='-') f=-1;
17 ch=getchar();
18 }
19 while (ch>='0'&&ch<='9'){
20 x=x*10+ch-'0';
21 ch=getchar();
22 }
23 return x*f;
24 }
25 int Tree_Solve(int fa,int num){
26 if (Ans[fa][num]>=0) return (Ans[fa][num]);
27 int cnt=Tree_Solve(T[fa].r,num);//全部取右孩子
28 for (int k=0;k<num;k++)
29 cnt=max(cnt,Tree_Solve(T[fa].l,k)+Tree_Solve(T[fa].r,num-k-1)+T[fa].value);
30 Ans[fa][num]=cnt;
31 return cnt;
32 }
33 int main(){
34 freopen("input.in","r",stdin);
35 freopen("output.out","w",stdout);
36 n=read(),m=read();
37 memset(f,0,sizeof(f));
38 for (int i=0;i<=n;i++)
39 T[i].l=T[i].r=400;//边界
40 //读入并建树(多叉树转化为二叉树)
41 for (int i=1;i<=n;i++){
42 int a=read(),b=read();
43 T[i].value=b;
44 if (!f[a]) T[a].l=i;
45 else T[f[a]].r=i;//相当于一条链
46 f[a]=i;
47 }
48 //DP:memoried search
49 memset(Ans,-1,sizeof(Ans));
50 for (int i=0;i<=n;i++)//边界一定要考虑详细
51 Ans[i][0]=0,Ans[400][i]=0;
52 printf("%d",Tree_Solve(T[0].l,m));
53 return 0;
54 }