• codevs 5565 二叉苹果树 树形DP


    5565 二叉苹果树

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
    题目描述 Description

          有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
           给定需要保留的树枝数量,求出最多能留住多少苹果。

    输入描述 Input Description

        第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
       N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
    每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
    每根树枝上的苹果不超过30000个。

    输出描述 Output Description

    剩余苹果的最大数量。

    样例输入 Sample Input

    5 2

    1 3 1

    1 4 10

    2 3 20

    3 5 20

    样例输出 Sample Output

    21

    数据范围及提示 Data Size & Hint

    对于20%数据 n<=20;

    对于100%数据1<N<=100,1<=Q<= N.

     --------------------------------------------------------------------------------------------------------------------------------------------

    很简单的一道树形DP,思路是 先把二叉树各边边权值转移到子节点上(这么做才能确定各点的状态),这样点x的状态即 点x的子树(包括点x)上保留y个点所得的最大值,开二维数组储存状态即dp[x][y],然后一遍DFS确定dp[x][1]的值,即等于点x的权值,然后在回溯时进行状态转移,不难得出状态转移方程为:

    dp[x][i]=max(dp[l[x]][j]+dp[r[x]][i-j-1]+dp[x][1],dp[x][i])。但要注意的问题是,最后还要对根节点进行一次状态转移:dp[1][Q]=max(dp[l[1]][i]+dp[r[1]][Q-i],dp[1][Q]),因为点权之前是由边权转移而来,而根节点没有参与边权的转移,故需要分开来。AC代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #define maxn 233
     4 struct node{
     5     int to,next,w;
     6 };
     7 node e[maxn];
     8 int N,Q,dp[maxn][maxn],pre[maxn],cnt,l[maxn],r[maxn];
     9 bool vis[maxn];
    10 int read();
    11 int max(int,int);
    12 void dfs(int);
    13 void build(int,int,int);
    14 int main(){
    15     memset(dp,0,sizeof(dp));
    16     memset(vis,0,sizeof(vis));
    17     memset(dp,0,sizeof(dp));
    18     N=read();Q=read();cnt=0;
    19     for(int i=1;i<N;i++){
    20         int a=read(),b=read(),c=read();
    21         build(a,b,c);
    22     }
    23     dfs(1);
    24     for(int i=0;i<=Q;i++) 
    25     dp[1][Q]=max(dp[l[1]][i]+dp[r[1]][Q-i],dp[1][Q]);
    26     printf("%d",dp[1][Q]);
    27     return 0;
    28 }
    29 int read(){
    30     int ans=0,f=1;char c=getchar();
    31     while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();}
    32     while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;
    33 }
    34 void build(int x,int y,int z){
    35     e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;e[cnt].w=z;
    36     e[++cnt].to=x;e[cnt].next=pre[y];pre[y]=cnt;e[cnt].w=z;
    37 }
    38 void dfs(int x){
    39     if(!vis[x]){
    40         vis[x]=1;
    41         bool po=1;
    42         for(int i=pre[x];i;i=e[i].next){
    43             int to=e[i].to;
    44             if(!vis[to]){
    45                 dp[to][1]=e[i].w;
    46                 if(po)l[x]=to,po=0;
    47                 else r[x]=to; 
    48             }
    49             dfs(to);
    50         }
    51         for(int i=2;i<=Q;i++)
    52             for(int j=0;j<i;j++)
    53                dp[x][i]=max(dp[l[x]][j]+dp[r[x]][i-j-1]+dp[x][1],dp[x][i]);
    54     }
    55 }
    56 int max(int x,int y){
    57     return x>y?x:y;
    58 }
    二叉苹果树

    其实自己还有一个思路,就是把状态定为 x点的子树中保留y条边时的最大值,这样就可以只有一条状态转移方程,但个人觉得处理起来没有第一种思路好。

  • 相关阅读:
    [LintCode] Valid Palindrome 验证回文字符串
    [LeetCode] 378. Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素
    [LintCode] Integer to Roman 整数转化成罗马数字
    [LintCode] Roman to Integer 罗马数字转化成整数
    [LintCode] Scramble String 爬行字符串
    [LintCode] Count and Say 计数和读法
    [LintCode] Simplify Path 简化路径
    [LintCode] Length of Last Word 求末尾单词的长度
    [LintCode] Valid Parentheses 验证括号
    [LeetCode] 377. Combination Sum IV 组合之和之四
  • 原文地址:https://www.cnblogs.com/lpl-bys/p/7384402.html
Copyright © 2020-2023  润新知