[关闭]
@Junlier 2018-08-31T22:10:27.000000Z 字数 1323 阅读 2001

luogu2014选课(树形dp)

动态规划——树形dp
题目传送门

方法

  • 先摆出状态再看怎么来的
    dp[i][j]表示以i为根的子树选了j门课的最大点权和(学分)
  • 因为选了儿子必须选爸爸,那么儿子的状态确定后(最大学分),爸爸转移的一种方式就确定了
  • 那我们考虑转移(父节点:now,儿子节点:qw)
    先看转移再解释:(j,k为枚举的选的课的数量)(暂时没有算上选now的值)
    dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[qw][k])
  • 显然,我如果在之前的儿子上转移出来了dp[now][j-k],那么和dp[qw][k]拼起来就是想要的状态了,但是注意一点:我们只是还没有把now的权值加进去,但是我们要假设它加进去了,以便转移,转移完之后再统一加上:dp[now][j]+=v[now](枚举j)

Code

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<cstdio>
  4. #include<cmath>
  5. #include<cstring>
  6. #include<iomanip>
  7. #include<algorithm>
  8. #include<ctime>
  9. #include<queue>
  10. #include<stack>
  11. #include<vector>
  12. #define rg register
  13. #define il inline
  14. #define lst long long
  15. #define ldb long double
  16. #define N 350
  17. using namespace std;
  18. const int Inf=1e9;
  19. il int read()
  20. {
  21. rg int s=0,m=0;rg char ch=getchar();
  22. while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
  23. while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
  24. return m?-s:s;
  25. }
  26. int n,m;
  27. int fa[N],v[N];
  28. int hd[N],cnt;
  29. int dp[N][N];
  30. struct EDGE{int to,nxt;}ljl[N<<1];
  31. il void add(rg int p,rg int q){ljl[++cnt]=(EDGE){q,hd[p]},hd[p]=cnt;}
  32. void dfs(rg int now)
  33. {
  34. for(rg int i=hd[now];i;i=ljl[i].nxt)
  35. {
  36. rg int qw=ljl[i].to;
  37. dfs(qw);
  38. for(rg int j=m;j>=1;--j)
  39. for(rg int k=j-1;k>=0;--k)
  40. dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[qw][k]);
  41. }
  42. for(rg int j=1;j<=m;++j)
  43. dp[now][j]+=v[now];
  44. }
  45. int main()
  46. {
  47. n=read(),m=read();m++;
  48. for(rg int i=1;i<=n;++i)
  49. {
  50. fa[i]=read(),v[i]=read();
  51. add(fa[i],i);
  52. }
  53. dfs(0);
  54. printf("%d\n",dp[0][m]);
  55. return 0;
  56. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注