zoukankan      html  css  js  c++  java
  • FZU1022 三色二叉树

    Problem Description  题目链接

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

    例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。

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

     Input

    输入数据由多组数据组成。
    每组数据仅有一行,不超过10000个字符,表示一个二叉树序列。

     Output

    对于每组输入数据,输出仅一行包含两个整数,依次表示最多和最少有多少个点能够被染成绿色。

     Sample Input

    1122002010

     Sample Output

    5 2
    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;
    #define N 100010
    
    /*
        思路:树形dp题注意将树的序列映射成二叉树,根据图形和序列可观察,序列是按先序二叉树给出,序列长度就为二叉树节点个数,并且第一个为根节点
    
        状态转移方程: 其中1表示最大值 0表示最小值
        dp[i][green][0]表示以节点i为根节点的子树中含有绿色个数的最小值,其中节点i为绿色
    
        若有俩个孩节点
        dp[i][green][0]=min(dp[i->leftChild][red][0]+dp[i->rightChild][blue][0],dp[i->leftChild][blue][0]+dp[i->rightChild][red][0])+1  除了绿色其他颜色不需要+1
    
        若有1个孩节点 统一映射在左孩子
        dp[i][green][0]=min(dp[i->leftChild][red][0],dp[i->leftChild][blue][0])+1  除了绿色其他颜色不需要+1
        
        若无孩节点有
        dp[i][green][0]=1 dp[i][red][0]=0
        
    */
    
    enum color
    {
        red = 0,
        green = 1,
        blue = 2
    };
    
    int dp[N][3][2], index; //Trees[1]表示编号为1的节点
    struct TreeNode
    {
        int leftChild, rightChild; //表示左右子节点的ID 若为0说明为不存在子节点
    } Trees[N];
    
    //映射二叉树 先序遍历
    void MapBinTree(string &str)
    {
        if (index >= str.size())
            return;
        if (str[index] == '0')
        { //说明没有子节点返回
            Trees[index].leftChild = 0;
            Trees[index].rightChild = 0;
            index++;
            return;
        }
        else if (str[index] == '1')
        {
            //说明只有一个子节点 子节点就为先序下一个遍历的节点
            Trees[index].leftChild = index + 1;
            Trees[index].rightChild = 0;
            index++;
            MapBinTree(str);
        }
        else //说明有俩个孩子节点
        {
            int temp = index;
            index++;
            //先序下一个节点为左孩子
            Trees[temp].leftChild = index;
            //拓展左节点
            MapBinTree(str);
            //拓展右节点
            Trees[temp].rightChild = index;
            MapBinTree(str);
        }
    }
    
    int main()
    {
        string seq; //seq节点编号会与Trees编号对应
        while (cin >> seq)
        {
            index = 0;
            MapBinTree(seq);
            index = seq.size() - 1;
            //从后往前递归即可遍历所有节点
            while (index >= 0)
            {
                //说明有俩个节点
                if (seq[index] == '2')
                {
                    dp[index][green][1] = max(dp[Trees[index].leftChild][red][1] + dp[Trees[index].rightChild][blue][1], dp[Trees[index].leftChild][blue][1] + dp[Trees[index].rightChild][red][1]) + 1;
                    dp[index][blue][1] = max(dp[Trees[index].leftChild][red][1] + dp[Trees[index].rightChild][green][1], dp[Trees[index].leftChild][green][1] + dp[Trees[index].rightChild][red][1]);
                    dp[index][red][1] = max(dp[Trees[index].leftChild][green][1] + dp[Trees[index].rightChild][blue][1], dp[Trees[index].leftChild][blue][1] + dp[Trees[index].rightChild][green][1]);
    
                    dp[index][green][0] = min(dp[Trees[index].leftChild][red][0] + dp[Trees[index].rightChild][blue][0], dp[Trees[index].leftChild][blue][0] + dp[Trees[index].rightChild][red][0]) + 1;
                    dp[index][blue][0] = min(dp[Trees[index].leftChild][red][0] + dp[Trees[index].rightChild][green][0], dp[Trees[index].leftChild][green][0] + dp[Trees[index].rightChild][red][0]);
                    dp[index][red][0] = min(dp[Trees[index].leftChild][green][0] + dp[Trees[index].rightChild][blue][0], dp[Trees[index].leftChild][blue][0] + dp[Trees[index].rightChild][green][0]);
                }
                //一个节点
                else if (seq[index] == '1')
                {
                    dp[index][green][1] = max(dp[Trees[index].leftChild][red][1], dp[Trees[index].leftChild][blue][1]) + 1;
                    dp[index][blue][1] = max(dp[Trees[index].leftChild][red][1], dp[Trees[index].leftChild][green][1]);
                    dp[index][red][1] = max(dp[Trees[index].leftChild][green][1], dp[Trees[index].leftChild][blue][1]);
    
                    dp[index][green][0] = min(dp[Trees[index].leftChild][red][0], dp[Trees[index].leftChild][blue][0]) + 1;
                    dp[index][blue][0] = min(dp[Trees[index].leftChild][red][0], dp[Trees[index].leftChild][green][0]);
                    dp[index][red][0] = min(dp[Trees[index].leftChild][green][0], dp[Trees[index].leftChild][blue][0]);
                }
                else
                {
                    dp[index][green][0] = 1;
                    dp[index][red][0] = 0;
                    dp[index][blue][0] = 0;
    
                    dp[index][green][1] = 1;
                    dp[index][red][1] = 0;
                    dp[index][blue][1] = 0;
                }
                index--;
            }
            //注意判断下 根节点不一定染绿
            printf("%d %d
    ", max(dp[0][green][1], max(dp[0][red][1], dp[0][blue][1])), min(dp[0][green][0], min(dp[0][red][0], dp[0][blue][0])));
        }
        return 0;
    }
     
  • 相关阅读:
    边框的各种样式
    内容溢出显示省略号
    UNIAPP开发注意事项
    css文本的三条线 删除线 下划线 上划线
    防抖截流
    浏览器窗口改变触发的函数
    ES5数组方法
    弹性布局
    ubuntu16.04 安装adb
    git clone
  • 原文地址:https://www.cnblogs.com/dlvguo/p/12772844.html
Copyright © 2011-2022 走看看