洛谷$2014$ 选课 背包类树形$DP$
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 }
光伴随的阴影