• 【洛谷题解/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
  • 相关阅读:
    hadoop 集群启动从节点无datanode
    使用小程序实现左侧菜单,右侧列表双向联动效果
    金蝶EAS本地WebService发布
    机械专业学子的芯片封装仿真“逆袭之路”
    刷题记录(NC13822 Keep In Line,NC16663 合并果子,NC16430 蚯蚓)
    11.Mogodb数据库基本使用
    通过 Nginx 实现多机负载均衡
    微信小程序框架
    Linux中,mysql设置job任务自动启动
    Vue3+Vite实现工程化,ref初次接触响应式和setup语法糖
  • 原文地址:https://blog.csdn.net/lightningcs/article/details/126449181