• [ZJOI2006] 三色二叉树


    树形dp

    题目传送门

    题目大意:给定一棵二叉树,将节点染成红、绿,蓝三种颜色,求绿色节点个数的最大值和最小值。

    这题建树十分恶心,需要一些技巧:

    观察输入数列及题面,可以知道任意一个节点的左子树一定在右子树的左边,且紧邻右子树

    这样就可以跑一个dfs,先搜左子树,记录左子树节点个数ln,则数组下标ln+1的数便是右子树的根,再搜右子树,记录节点个数rn,则ln+rn+1就是下一个要搜的点

    对于染色,每个节点可以分为两种情况:染绿色和不染绿色

    我们可以令f[i][0/1]表示以节点i为根的子树中,当i不染绿色/染绿色时,绿色节点个数的最大值,ff[i][0/1]同理,求最小值

    则当i有一个儿子时,f[i][1]=f[ls[i]][0]+1

    则当i有两个儿子时,f[i][0]=max(f[ls[i]][0]+f[rs[i]][1],f[rs[i]][0]+f[ls[i]][1])      f[i][1]=f[ls[i]][0]+f[rs[i]][0]+1

    求最小值同理

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    char c[1000005];
    int p[1000005];
    int n;
    int lst;
    int s[1000005];
    int f[1000005][2];
    int ff[1000005][2];
    int ls[1000005],rs[1000005];
    int build(int cur)
    {
        if(p[cur]==0) return 1;
        else if(p[cur]==1)
        {
            ls[cur]=cur+1;
            int t=build(cur+1);
            return t+1;
        }
        else
        {
            ls[cur]=cur+1;
            int t=build(cur+1);
            rs[cur]=cur+t+1;
            int tt=build(cur+t+1);
            return t+tt+1;
        }
    }
    void dfs(int i)
    {
        if(ls[i]!=0) dfs(ls[i]);
        if(rs[i]!=0) dfs(rs[i]);
        if(s[i]==1)
        {
            f[i][1]=f[ls[i]][0]+1;
            ff[i][1]=ff[ls[i]][0]+1;
            f[i][0]=max(f[ls[i]][0],f[ls[i]][1]);
            ff[i][0]=min(ff[ls[i]][0],ff[ls[i]][1]);
        }
        if(s[i]==2)
        {
            f[i][1]=f[ls[i]][0]+f[rs[i]][0]+1;
            ff[i][1]=ff[ls[i]][0]+ff[rs[i]][0]+1;
            f[i][0]=max(f[ls[i]][0]+f[rs[i]][1],f[rs[i]][0]+f[ls[i]][1]);
            ff[i][0]=min(ff[ls[i]][0]+ff[rs[i]][1],ff[rs[i]][0]+ff[ls[i]][1]);
        }
    }
    int main()
    {
        cin>>(c+1);
        n=strlen(c+1);
        for(int i=1;i<=n;i++) p[i]=c[i]-'0';
        build(1);
        for(int i=1;i<=n;i++)
        {
            if(ls[i]&&rs[i]) s[i]=2;
            else if(!ls[i]&&!rs[i]) s[i]=0;
            else s[i]=1;
            if(s[i]==0) f[i][1]=ff[i][1]=1;
        }
        dfs(1);
        //for(int i=1;i<=n;i++) cout<<i<<' '<<f[i][0]<<' '<<f[i][1]<<endl;
        cout<<max(f[1][0],f[1][1])<<' '<<min(ff[1][1],ff[1][0])<<endl;
        return 0;
    }

    谷歌输入法真™难用

  • 相关阅读:
    yii2 分页
    yii2 钩子函数
    linux 配置compoer
    Python随心记--迭代器协议和for循环机制
    Python随心记--文件操作处理 open()
    Python随心记--练习
    Python随心记--函数式编程及常用内置函数,及部分实例
    Python随心记--匿名函数
    Python随心记--函数作用域
    Python随心记--局部变量与全局变量
  • 原文地址:https://www.cnblogs.com/ssf-xiaoban/p/11614853.html
Copyright © 2020-2023  润新知