• 树形DP初步-真树1662


    树形DP初步-真树

    时间限制: 1000 ms 内存限制: 65536 kb
    总通过人数: 119 总提交人数: 123

    题目描述

    新年到了,白兔家族要搞大大的聚会。但是并不是每只白兔都是同一辈分的,于是便有一棵以老白兔为根的家族树。

    每只白兔都有它们自己唯一的整数编号(范围在1到N之间),并且对应一个参加聚会所得的开心值。为了使每个参加聚会的白兔都巨开心,老白兔想让每只白兔和他的上一代白兔不会同时参加聚会。

    求参加聚会的白兔获得的最大总开心值。

    输入

    输入的第一行是一个整数N,1<= N <= 6000

    以下的N行是对应的N个白兔的开心值(开心值是一个从-128到127之间的整数)

    接着是白兔的家族树,树的每一行格式如下: 每行输入一对整数L,K。表示第K个白兔是第L个白兔的上一代。 输入以0 0表示结束

    输出

    参加聚会的白兔获得的最大总开心值

    输入样例

    7
    1
    1
    1
    1
    1
    1
    1
    1 3
    2 3
    6 4
    7 4
    4 5
    3 5
    0 0

    输出样例

    5

    AC代码
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #define maxn 6007
     5 using namespace std;
     6 
     7 int n;
     8 int dp[maxn][2],father[maxn];
     9 
    10 
    11 void tree_dp(int node)
    12 {
    13     int i;
    14     
    15     for(int i=1;i<=n;i++)             //对树遍历。树的深度游戏先搜索
    16     {
    17         if(father[i]==node)  
    18         {
    19             tree_dp(i);
    20             dp[node][1]+=dp[i][0];
    21             dp[node][0]+=max(dp[i][0],dp[i][1]);
    22         }
    23     }
    24 }
    25 
    26 int main()
    27 {
    28     int a,b;
    29     int root=0;
    30     scanf("%d",&n);
    31     for(int i=1;i<=n;i++)
    32     {
    33         scanf("%d",&dp[i][1]);
    34     }
    35     scanf("%d%d",&a,&b);
    36     while(!(a==0&&b==0))
    37     {
    38         father[a]=b;
    39         
    40         scanf("%d%d",&a,&b);
    41     }
    42     root=b;
    43     //找到根节点
    44     while(father[root])
    45     {
    46         root=father[root];
    47     }
    48     //从根节点开始dp
    49     tree_dp(root);
    50     printf("%d
    ",max(dp[root][0],dp[root][1]));
    51 }

    1.求相邻节点不同时取的最大节点权值和。
    2.考虑序列中相邻不同取的dp:f[i][0]表示前i个,i不取的最优值;f[i][1]表示前i个,i取的最值;
    同理到树形dp:f[i][0]表示i为根的子树中,i不取的最优值;f[i][1]同理。
    3.则在dfs过程中,顺道dp;
    4.f[i][0] = ∑max(f[j][1], f[j][0]),j为i的儿子;
    f[i][1] = a[i] + ∑f[j][0],j为i的儿子,a[i]为i自身的价值。
    5.答案为max(f[root][0], f[root][1])

    6.注:此题由于树的结构的特殊性,自顶向下生成时并不会产生子问题的重复计算(每棵子树只对它的父节点产生贡献,这棵子树的信息只被用到一次)



  • 相关阅读:
    (Java实现) 装载问题
    (Java实现) 子集和问题
    (Java实现) 子集和问题
    (Java实现) 整数区间
    (Java实现) 车厢重组
    (Java实现) 车厢重组
    (Java实现) 车厢重组
    (Java实现) 车厢重组
    delphi 程序窗体及控件自适应分辨率(通过ComponentCount遍历改变字体大小以及上下左右)
    后台开发:核心技术与应用实践(边写代码边读书才是最好的学习方式)
  • 原文地址:https://www.cnblogs.com/loganlzj/p/10093470.html
Copyright © 2020-2023  润新知