洛谷 P2014 [CTSC1997]选课(树形DP)

题目链接:https://www.luogu.com.cn/problem/P2014

一道树上关于点的0-1背包问题。

这道题背包容量实际为m,但是可以让背包容量为m+1,因为0这个似虚非虚的根是一定要选的,并且它的贡献为0。

那么方程式:$dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])$

其中,dp[u][j]表示以u为根,子树节点数为j的最大值。初始化的话:sum[u]=1,dp[u][1]=val[u],这是显然的。

不得不说树形DP的边界都好奇特。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=400;
 6 struct node{
 7     int to,next;
 8 }edge[N];
 9 int head[N],tot;
10 int dp[N][N],sum[N],n,m;
11 void add(int u,int v){
12     edge[tot].to=v;
13     edge[tot].next=head[u];
14     head[u]=tot++;
15 }
16 void DFS(int u,int fa){
17     sum[u]=1;
18     for(int i=head[u];i!=-1;i=edge[i].next){
19         int v=edge[i].to;
20         if(v==fa) continue;
21         DFS(v,u);
22         sum[u]+=sum[v];
23         for(int j=min(m+1,sum[u]);j>=1;j--){
24             for(int k=min(j-1,sum[v]);k>=0;k--){
25                 dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
26             }
27         }
28     }
29 }
30 int main(){
31     memset(head,-1,sizeof(head));
32     scanf("%d%d",&n,&m);
33     for(int i=1;i<=n;i++){
34         int s,k;
35         scanf("%d%d",&k,&s);
36         add(k,i); dp[i][1]=s;
37     }
38     DFS(0,-1);
39     printf("%d\n",dp[0][m+1]);
40     return 0;
41 }
AC代码

猜你喜欢

转载自www.cnblogs.com/New-ljx/p/12594164.html
今日推荐