• 树形Dp-二叉树(tree)


    题目描述

    从前有一棵二叉树,我们用如下方式来表示这棵二叉树。
    (1)如果一个节点没有儿子,我们用“0”来表示他。
    (2)如果一个节点有一个儿子,我们对它的表示以“1”开头,后面接对它儿子的表示。
    (3)如果一个节点有两个儿子,我们对它的表示以“2”开头,后面先接对它左儿子的
    表示,后接对它右儿子的表示。
    KJDH十分贪玩,将这棵树染了色,KJDH又十分聪明,它染色又很有规则:每个节点不
    能和它的孩子有相同的颜色,如果一个节点有两个孩子,那么这两个孩子也不能有相同的颜
    色。
    由于这个树年代久远了,所以我们看不清每个节点的颜色了,但我们知道KJDH只染了
    红黄白三种颜色。我们想知道这棵树最多和最少有多少个节点是白色的。
     

    输入

    输入文件名为tree.in。
    输入文件只有一行,一个字符串,只有“0”,“1”,“2”组成,表示这
    棵树的结构。
     

    输出

    输出文件名为tree.out。
    输出文件包含两个用空格隔开的数,分别表示白色节点的最多和最少数量。
     

           样例输入1                     样例输出1

       200             1 1

           样例输入2                     样例输出2

    1122002010         5 2

    Solution:
    容易看出是树形Dp,且属于那种比较简单的树形Dp

    由于要处理两个小问题,我们设f[i][0/1/2](0->白,1->红,2—>黄)来表示以i为根的子树最多有几个白色节点,

    g[i][0/1/2]则表示最小的情况

    首先我们要处理读入的问题,这里我采用了递归的方式,

    因为这里的节点其实是按照先序的方式来读入的,所以不断递归儿子到底后返回编号记入

    之后就是转移了,按照先序遍历的顺序来转移,也就是至下而上,转移方程其实抠抠脚就可以出来了:

    f[i][0]=max{f[u][1]+f[v][2],f[u][2]+f[v][1]}+1
    //u、v表示左右儿子的编号,最后+1是为i节点自己为白色所以要比填其他颜色多1
    f[i][1]=max{f[u][0]+f[v][2],f[u][2]+f[v][0]}
    f[i][2]=max{f[u][1]+f[v][0],f[u][0]+f[v][1]}
    最后把f[1][0],f[1][1],f[1][2]三个拿起来最大就是答案
    g的转移和结果同理,把max改min即可。

    Code:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int inf=500050;
     4 struct Node{
     5     int fa;
     6     int son[2];
     7 }Tree[inf];
     8 char Str[inf];
     9 int f[inf][3],g[inf][3],tot,Y;
    10 void Dfs(int pos){
    11     for(int i=0;i<=1;i++){
    12         if(!Tree[pos].son[i]) break;
    13         Dfs(Tree[pos].son[i]);
    14     }
    15     f[pos][0]=max(f[Tree[pos].son[0]][1]+f[Tree[pos].son[1]][2],f[Tree[pos].son[0]][2]+f[Tree[pos].son[1]][1])+1;
    16     f[pos][1]=max(f[Tree[pos].son[0]][0]+f[Tree[pos].son[1]][2],f[Tree[pos].son[0]][2]+f[Tree[pos].son[1]][0]);
    17     f[pos][2]=max(f[Tree[pos].son[0]][1]+f[Tree[pos].son[1]][0],f[Tree[pos].son[0]][0]+f[Tree[pos].son[1]][1]);
    18     g[pos][0]=min(g[Tree[pos].son[0]][1]+g[Tree[pos].son[1]][2],g[Tree[pos].son[0]][2]+g[Tree[pos].son[1]][1])+1;
    19     g[pos][1]=min(g[Tree[pos].son[0]][0]+g[Tree[pos].son[1]][2],g[Tree[pos].son[0]][2]+g[Tree[pos].son[1]][0]);
    20     g[pos][2]=min(g[Tree[pos].son[0]][1]+g[Tree[pos].son[1]][0],g[Tree[pos].son[0]][0]+g[Tree[pos].son[1]][1]);
    21 }
    22 int In(int F){
    23     Tree[++tot].fa=F;
    24     int a=Str[++Y]-'0',Num=tot;
    25     if(a>=1)
    26         Tree[Num].son[0]=In(Num);
    27     if(a>=2)
    28         Tree[Num].son[1]=In(Num);
    29     return Num;
    30 }
    31 using namespace std;
    32 int main()
    33 {
    34     freopen("tree.in","r",stdin);
    35     freopen("tree.out","w",stdout);
    36     scanf("%s",Str+1);
    37     In(0);
    38     Dfs(1);
    39     printf("%d %d",max(f[1][2],max(f[1][0],f[1][1])),min(g[1][2],min(g[1][0],g[1][1])));
    40     return 0;
    41 }
     
     
  • 相关阅读:
    [C++] 习题 2.18 倒序查找字串
    [C++] 二叉树计算文件单词数
    [C++] 例题 2.7.1 用栈实现简易计算器
    [C++] 非递归实现前中后序遍历二叉树
    [C++] 习题 2.15 实现简单环形队列
    数据结构、算法及应用
    [C++] 习题 2.14 用队列实现桶排序
    svn add 所有文件的命令
    解决Error opening terminal: xterm.的错误
    linux下删除项目中所有.svn的命令
  • 原文地址:https://www.cnblogs.com/Takarada-Rikka/p/11824775.html
Copyright © 2020-2023  润新知