zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Linnia学习记录
    漫漫考研路
    ENS的学习记录
    KnockoutJS 3.X API 第四章 数据绑定(4) 控制流with绑定
    KnockoutJS 3.X API 第四章 数据绑定(3) 控制流if绑定和ifnot绑定
    KnockoutJS 3.X API 第四章 数据绑定(2) 控制流foreach绑定
    KnockoutJS 3.X API 第四章 数据绑定(1) 文本及样式绑定
    KnockoutJS 3.X API 第三章 计算监控属性(5) 参考手册
    KnockoutJS 3.X API 第三章 计算监控属性(4)Pure computed observables
    KnockoutJS 3.X API 第三章 计算监控属性(3) KO如何实现依赖追踪
  • 原文地址:https://www.cnblogs.com/WABoss/p/5292749.html
Copyright © 2011-2022 走看看