树形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);
}
posted @ 2020-05-29 18:25  HH_Halo  阅读(223)  评论(0编辑  收藏  举报