• 【洛谷题解/ZJOI2005】P2585 三色二叉树


    原题链接:https://www.luogu.com.cn/problem/solution/P2585
    难度:提高+/省选-
    涉及知识点:树上DP

    题意

    给定一个“二叉树序列” S S S,要求根据题目描述建树。
    建树规则
    要求对二叉树进行染色,可以染成蓝色、绿色或红色,但是,一个节点的颜色不能与其子节点相同,求这棵二叉树最多和最少能被染成绿色。

    分析与解决

    先回顾一下“没有上司的舞会”一题的解决方法,如果一个父节点不选,我们就把该节点的每个子节点选或不选的开心值的较大 D P DP DP 值累加起来,如果一个父节点选,就把该节点的每个节点不选时的最大 D P DP DP 值累加起来,通过这样分类讨论的方式求出了答案,显然“三色二叉树”一题也是可以类比的。

    首先定义 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1] 为节点 i i i 被染成绿色或不被染成绿色时,在其子树(包括自己)被染成绿色的最多节点数,0 表示不被染成绿色,1 表示被染成绿色。

    一个节点是不是被染成蓝色或红色我们不关心,可以一概被归类到“除绿色外的其他颜色”,我们只关心一个节点被染或不染成绿色的情况,分下面两种情况讨论:

    • 如果该节点被染成绿色,那么就累加左右子节点不染绿色时的最大 f f f 值再加1(因为该节点染色了)
    • 如果节点不被染成绿色,那么就对左子节点染绿色和右子节点染绿色的两种情况取最值。

    最后输出时,对根节点染成绿色和不染成绿色两种情况取最值即可。
    至于建树,用递归方式,用数组存储,依次判断序列中的每个数并作出相应的处理。

    AC代码

    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 5e5 + 10;
    char s[N]; //二叉树序列
    int cnt, n;
    int tr[N][2]; //树
    int f[N][2];
    
    void dfs(int u)
    {
        cnt++;
        if (s[u] == '0') return; //没有子节点
        else if (s[u] == '1')
        {
            tr[u][0] = u + 1; //左子节点
            dfs(u + 1);
        }
        else if (s[u] == '2')
        {
            tr[u][0] = u + 1; //左子节点
            dfs(u + 1);
            tr[u][1] = cnt + 1; //右子节点
            dfs(cnt + 1);
        }
    }
    
    int main()
    {
        scanf("%s", s + 1);
        dfs(1); //递归建树
        n = strlen(s + 1);
    
        for (int i = n; i >= 1; i--)
        {
            //1.父节点染成绿色
            //2.左子节点或者右子节点染成绿色
            f[i][1] = f[tr[i][0]][0] + f[tr[i][1]][0] + 1;
            f[i][0] = max(f[tr[i][0]][1] + f[tr[i][1]][0], f[tr[i][0]][0] + f[tr[i][1]][1]);
        }
        cout << max(f[1][0], f[1][1]) << " ";
        for (int i = n; i >= 1; i--)
        {
            //1.父节点染成绿色
            //2.左子节点或者右子节点染成绿色
            f[i][1] = f[tr[i][0]][0] + f[tr[i][1]][0] + 1;
            f[i][0] = min(f[tr[i][0]][1] + f[tr[i][1]][0], f[tr[i][0]][0] + f[tr[i][1]][1]);
        }
        cout << min(f[1][0], f[1][1]);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    妈妈的爱,从口腔微生物开始
    详解欧拉计划第349题:兰顿的蚂蚁
    CronJob运行自动化任务
    FPGA在汽车领域的应用简谈
    Redis整理
    3. executors
    软件需求分析一般应确定的是用户对软件的(功能需求和非功能需求 ),结构化设计是一种面向(数据流 )的设计方法
    Linux篇17多线程第一部分
    [Codeforces] combinatorics (R1200) Part.1
    【youcans动手学模型】目标检测之 SPPNet 模型
  • 原文地址:https://blog.csdn.net/lightningcs/article/details/126449181