• 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 }
  • 相关阅读:
    cad三维多断线的合并
    将list中的每个元素转换成str
    ndarray格式的点云数组转变为open3d.open3d.geometry.PointCloud
    汉字读音积累
    python文件内的函数调用
    numpy.dot()函数
    父亲啊,儿子是您永远的牵挂
    2008江西高考0分作文
    记忆一个朋友
    暴风雨前的天空
  • 原文地址:https://www.cnblogs.com/WABoss/p/5292749.html
Copyright © 2020-2023  润新知