洛谷$2014$ 选课 背包类树形$DP$

luogu

 

Sol

阶段和状态都是树形DP板子题,这里只讲一下背包的部分(转移)叭

它其实是一个分组背包模型,具体理解如下:

对于一个结点x,它由它的子结点y转移而来

在子结点y为根的树中可以选不同数量的课程,这些就可以看成一个组内的物品

具体来说,f[y][1],f[y][2],f[y][3]...这些都是一个组里的,只能选一样

注意每组内的物品只能选一样,所以枚举体积要倒序

over!

 

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 using namespace std;
 6 int r()
 7 {
 8     int x=0,y=1;;char ch;
 9     ch=getchar();
10     while(ch<'0'||ch>'9') {if(ch=='-') y=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}   
12     return x*y;
13 }
14 int n,m;
15 vector<int> son[310];
16 int s[310];
17 int f[310][310];
18 void dp(int x)
19 {
20     //f[x][0]=0;
21     for(int i=0;i<son[x].size();i++)
22     {
23         int y=son[x][i];
24         dp(y);
25         for(int a=m;a>=0;a--)//倒序!
26             for(int b=0;b<=a;b++)
27                 f[x][a]=max(f[x][a],f[x][a-b]+f[y][b]);
28     }
29     if(x!=0)
30     {
31         for(int i=m;i>0;i--)
32             f[x][i]=f[x][i-1]+s[x];
33     }
34 }
35 int main()
36 {
37     n=r();m=r();
38     for(int i=1;i<=n;i++)
39     {
40         int x=r();s[i]=r();
41         son[x].push_back(i);
42     } 
43     //memset(f,0xcf,sizeof(f));
44     dp(0);
45     cout<<f[0][m];
46     return 0;
47 }
View Code

 

posted @ 2019-06-11 11:09  DTTTTTTT  阅读(155)  评论(0编辑  收藏  举报