POJ2486 Apple Tree(树形DP)

题目大概是一棵树,每个结点都有若干个苹果,求从结点1出发最多走k步最多能得到多少个苹果。

考虑到结点可以重复走,容易想到这么个状态:

  • dp[u][k][0]表示在以结点u为根的子树中走k步且必须返回u能得到的最多苹果
  • dp[u][k][1]表示在以结点u为根的子树中走k步且可以不返回u能得到的最多苹果
  • 单纯这样转移又是指数级的时间复杂度,所以又是树上背包了

转移就是:

  • dp[u][k][0]=max(dp[u][k][0],dp[v][k'][0]+dp[u][k-k'-2][0])(v是u当前的孩子),对于必须返回的就是从u走一步到v,分k‘个给当前的子树v走并走回v,最后再走一步返回u
  • dp[u][k][1]=max(dp[u][k][1],dp[v][k'][1]+dp[u][k-k'-1][0])(v是u当前的孩子),之前的子树走完回到u,走一步到v,最后不返回地在当前的子树v中走k‘步

不过这样提交WA。。然而看不出哪里有错。。无奈看别人代码,发现转移少考虑了一种情况——

  • dp[u][k][1]=max(dp[u][k][1],dp[v][k'][0]+dp[u][k-k'-2][1])(v是u当前的孩子),从u走一步到v,分配k'步给当前子树v走并返回v,再走一步回到u,最后不返回地向之前的子树走

真的想不到。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define MAXN 111
 6 struct Edge{
 7     int v,next;
 8 }edge[MAXN<<1];
 9 int NE,head[MAXN];
10 void addEdge(int u,int v){
11     edge[NE].v=v; edge[NE].next=head[u];
12     head[u]=NE++;
13 }
14 int d[MAXN][222][2];
15 int n,m,apple[MAXN];
16 void dp(int u,int fa){
17     d[u][0][0]=d[u][0][1]=apple[u];
18     for(int i=head[u]; i!=-1; i=edge[i].next){
19         int v=edge[i].v;
20         if(v==fa) continue;
21         dp(v,u);
22         for(int j=m; j>0; --j){
23             for(int k=0; k<j; ++k){
24                 if(d[v][k][1]==-1 || d[u][j-k-1][0]==-1) continue;
25                 d[u][j][1]=max(d[u][j][1],d[v][k][1]+d[u][j-k-1][0]);
26             }
27             for(int k=0; k<j-1; ++k){
28                 if(d[v][k][0]==-1 || d[u][j-k-2][1]==-1) continue;
29                 d[u][j][1]=max(d[u][j][1],d[v][k][0]+d[u][j-k-2][1]);
30             }
31             for(int k=0; k<j-1; ++k){
32                 if(d[v][k][0]==-1 || d[u][j-k-2][0]==-1) continue;
33                 d[u][j][0]=max(d[u][j][0],d[v][k][0]+d[u][j-k-2][0]);
34             }
35         }
36     }
37 }
38 int main(){
39     int a,b;
40     while(~scanf("%d%d",&n,&m)){
41         NE=0;
42         memset(head,-1,sizeof(head));
43         for(int i=1; i<=n; ++i) scanf("%d",apple+i);
44         for(int i=1; i<n; ++i){
45             scanf("%d%d",&a,&b);
46             addEdge(a,b); addEdge(b,a);
47         }
48         memset(d,-1,sizeof(d));
49         dp(1,1);
50         int res=-1;
51         for(int i=0; i<=m; ++i){
52             res=max(res,d[1][i][1]);
53         }
54         printf("%d
",res);
55     }
56     return 0;
57 }
原文地址:https://www.cnblogs.com/WABoss/p/5292749.html