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;
    }
  • 相关阅读:
    手把手教会你如何通过C#创建Windows Service
    推荐几款软件界面模型设计工具
    visual studio 2010小技巧
    C# 枚举在属性中运用
    C# Stream 和 byte[] 之间的转换
    推荐一款DataGridView的打印解决方案
    VB提高专辑VB编写自定义类(下)
    vb 怎么把长整型转字符串
    Android NAND: nand_dev_load_disk_state, restore failed: size required (3546398242485400641) exceeds device limit (6920
    VB中各种类型的转换
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673461.html
Copyright © 2011-2022 走看看