zoukankan      html  css  js  c++  java
  • 树形dp——三色二叉树

    题目描述

    一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:

    0 该树没有子节点 1S1 该树有一个子节点,S1为其二叉树序列 1S1S2 该树有两个子节点,S1,S2分别为两个二叉树的序列 例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。

    你的任务是要对一棵二叉树的节点进行染色。每个节点可以被染成红色、绿色或蓝色。并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。 image

    输入格式

    输入文件仅有一行,不超过10000个字符,表示一个二叉树序列

    输出格式

    输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

    样例

    样例输入

    1122002010
    

    样例输出

    5 2
    

    题目分析

    讲真第一眼看见这道题想起了刚学的排列组合emmm

    • 这题看起来花里胡哨,其实搞懂题以后,还是比较暴力的
    • 关键点:
      • 如何建树:根据题意,子串的每一个字符都代表着分支,重点在分支为0这里,分支为0说明走到了根节点,直接返回即可
      • 转移方程:每个点都可以涂三种颜色,每种颜色都试一下,加上子树的dp值,而且要分开保存,最大值最小值要分开,不同的颜色也要分开,最后统一比较即可
    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn =1e4+10;
    char s[maxn];
    int f1[maxn][3],f2[maxn][3];//f1是最大值,f2是最小值,再多开一维数组记录所涂颜色
    int dfs(int root){ //返回每个子树跑dfs的末尾元素
        if(s[root] == '0'){
            f1[root][0] = f2[root][0] = 1;
            return root;
        }
        int left = dfs(root+1);
        if(s[root] == '1'){//根据颜色的互异性,直接分情况讨论
            f1[root][0] = max(f1[root+1][1],f1[root+1][2])+1; 
            f1[root][1] = max(f1[root+1][0],f1[root+1][2]); 
            f1[root][2] = max(f1[root+1][0],f1[root+1][1]);
            f2[root][0] = min(f2[root+1][1],f2[root+1][2])+1;
            f2[root][1] = min(f2[root+1][0],f2[root+1][2]);
            f2[root][2] = min(f2[root+1][0],f2[root+1][1]);
            return left;
        }
        if(s[root] == '2'){//有两个子树,还需要从左子树的末尾接着跑,找出右子树
            int right = dfs(left+1);
            f1[root][0] = max(f1[root+1][1]+f1[left+1][2],f1[root+1][2]+f1[left+1][1])+1; 
            f1[root][1] = max(f1[root+1][0]+f1[left+1][2],f1[root+1][2]+f1[left+1][0]); 
            f1[root][2] = max(f1[root+1][0]+f1[left+1][1],f1[root+1][1]+f1[left+1][0]);
            f2[root][0] = min(f2[root+1][1]+f2[left+1][2],f2[root+1][2]+f2[left+1][1])+1;
            f2[root][1] = min(f2[root+1][0]+f2[left+1][2],f2[root+1][2]+f2[left+1][0]);
            f2[root][2] = min(f2[root+1][0]+f2[left+1][1],f2[root+1][1]+f2[left+1][0]);
            return right;
        }
    }
    
    int main(){
        cin>>s;
        dfs(0);
        int MAX = max(f1[0][0],max(f1[0][1],f1[0][2]));//三种情况进行比较,得出最大值
        int MIN = min(f2[0][0],min(f2[0][1],f2[0][2]));//得出最小值
        printf("%d %d",MAX,MIN);
    }
    
  • 相关阅读:
    常用Git代码托管服务分享
    .NET中操作IPicture、IPictureDisp
    Git学习笔记与IntelliJ IDEA整合
    螺旋队列问题
    杂题3道
    .NET 配置文件简单使用
    C++之Effective STL
    不容易理解的 lock 和 merge
    状态模式
    观察者模式
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/12989024.html
Copyright © 2011-2022 走看看