zoukankan      html  css  js  c++  java
  • bzoj1864 [Zjoi2006]三色二叉树

    Description

    这里写图片描述

    Input

    仅有一行,不超过500000个字符,表示一个二叉树序列。

    Output

    输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

    Sample Input
    1122002010

    Sample Output
    5 2

    分析:
    第一次写dp1A,✿✿ヽ(°▽°)ノ✿
    如果一个节点被染成绿色,那么ta的父亲,儿子和最近兄弟都不能是绿色
    也就是说,一个绿色节点最多影响4个节点,最少影响1个
    设计状态
    f[i][0/1/2]
    当前i节点,状态是0/1/2,最多有多少个绿色节点
    g[i][0/1/2]
    当前i节点,状态是0/1/2,最少有多少个绿色节点

    tip

    转移的时候耐下心来慢慢写就好
    (瞎扯,ctrl+c和ctrl+v就好)

    觉得唯一有点难度的就是怎么把序列还原成树的形态
    dfs,记一个bh(常函数)
    bh只加不减,表示序列中的指针右移

    这里写代码片
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    
    using namespace std;
    
    const int N=500001;
    char s[N];
    int f[N][3],g[N][3],fa[N<<1],bh,ch[N][2];
    
    void dfs(int faa)
    {
        bh++;  //当前位置 
        ch[faa][ch[faa][0] ? 1:0]=bh;
        fa[bh]=faa;
        int x=s[bh-1]-'0';
        int r=bh;  //局部变量,保证儿子能精准的找到爸爸
        if (x==2)  //两个儿子 
        {
            dfs(r);
            dfs(r);
        }
        else if (x==1)
        {
            dfs(r);
        }
        else return;
    }
    
    void doit(int now)
    {
        if (ch[now][0]) doit(ch[now][0]);   //dp son
        if (ch[now][1]) doit(ch[now][1]);
        if (!ch[now][0]&&!ch[now][1])  //leave
        {
            f[now][0]=0;f[now][1]=0;f[now][2]=1;  //two means G
            g[now][0]=0;g[now][1]=0;g[now][2]=1;  //two means G
            return;
        }
        else if (ch[now][0]&&ch[now][1])  //two sons
        {
            f[now][0]=max(f[ch[now][0]][2]+f[ch[now][1]][1],f[ch[now][0]][1]+f[ch[now][1]][2]);
            f[now][1]=max(f[ch[now][0]][2]+f[ch[now][1]][0],f[ch[now][0]][0]+f[ch[now][1]][2]);
            f[now][2]=max(f[ch[now][0]][0]+f[ch[now][1]][1],f[ch[now][0]][1]+f[ch[now][1]][0])+1;
            g[now][0]=min(g[ch[now][0]][2]+g[ch[now][1]][1],g[ch[now][0]][1]+g[ch[now][1]][2]);
            g[now][1]=min(g[ch[now][0]][2]+g[ch[now][1]][0],g[ch[now][0]][0]+g[ch[now][1]][2]);
            g[now][2]=min(g[ch[now][0]][0]+g[ch[now][1]][1],g[ch[now][0]][1]+g[ch[now][1]][0])+1;
        }
        else if (ch[now][0])
        {
            f[now][0]=max(f[ch[now][0]][2],f[ch[now][0]][1]);
            f[now][1]=max(f[ch[now][0]][2],f[ch[now][0]][0]);
            f[now][2]=max(f[ch[now][0]][0],f[ch[now][0]][1])+1;
            g[now][0]=min(g[ch[now][0]][2],g[ch[now][0]][1]);
            g[now][1]=min(g[ch[now][0]][2],g[ch[now][0]][0]);
            g[now][2]=min(g[ch[now][0]][0],g[ch[now][0]][1])+1;
        }
        else
        {
            f[now][0]=max(f[ch[now][1]][2],f[ch[now][1]][1]);
            f[now][1]=max(f[ch[now][2]][2],f[ch[now][1]][0]);
            f[now][2]=max(f[ch[now][2]][0],f[ch[now][1]][1])+1;
            g[now][0]=min(g[ch[now][1]][2],g[ch[now][1]][1]);
            g[now][1]=min(g[ch[now][2]][2],g[ch[now][1]][0]);
            g[now][2]=min(g[ch[now][2]][0],g[ch[now][1]][1])+1;
        }
    }
    
    int main()
    {
        scanf("%s",&s);
        bh=0;
        dfs(0);   //还原树的形态 
        doit(1);
        int f1=max(f[1][0],max(f[1][1],f[1][2]));
        int f2=min(g[1][0],min(g[1][1],g[1][2]));
        printf("%d %d",f1,f2);
        return 0;
    }
  • 相关阅读:
    sublime text 3安装 package control 插件的方法
    mysql 库和表占用空间查询
    错误:编码GBK的不可映射字符
    新系统设置 github 私钥
    git 之忽略文件 gitignore 创建和使用规则
    DesiredCapabilities内容详解(摘)
    appium-python自动化之get_attribute笔记(摘)
    excel批量插入图片-方法(宏和纯手工操作)
    利用Python将多个excel文件合并为一个文件
    notePad++ 运行python
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673460.html
Copyright © 2011-2022 走看看