• P2585 [ZJOI2006]三色二叉树 树形Dp


    输入格式

    输入文件仅有一行,不超过10000个字符,表示一个二叉树序列

    输出格式

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

    样例

    样例输入

    1122002010
    

    样例输出

    5 2


    可以用f[i][0],f[i][1],f[i][2]分别表示当i被染成绿色,红色,蓝色时,以i为根节点的子树最多能被染成绿色的点数
    (注意不要误认为是各颜色的最多点数,是最多绿色点数
    ff来表示最少点数。

    之后就按照题目描述去模拟了。
    (最开始我打算先用结构体建树,再dfs,但直接邻接矩阵dfs更方便(毕竟塔是个二叉树

    目标:ans=max(f[1][x],x=0或1或2)和 anss=min(ff[1][x],x=0或1或2).

    (有些坑标注在代码里面了...每一个栽进去都是满满的疼啊...

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN = 1e4+10;
    typedef long long ll;
    
    int f[MAXN][4],ff[MAXN][4],now,ans=1,anss;
    char a[MAXN];
    
    void dfs(int i){//i为节点编号
        if(a[i]=='0'){//i为叶子结点,以叶子结点为子树的树只有它自己
            f[i][0]=ff[i][0]=1; return;//i为绿色,则最多最少都是1
        }
        dfs(++now);//dfs左儿子(左儿子编号一定为i+1,也就是now+1),为下面求i的函数值做铺垫
        if(a[i]=='1'){//如果i只有一个儿子
            f[i][0]=max(f[i+1][1],f[i+1][2])+1;//当i为绿色,点数+1
            f[i][1]=max(f[i+1][0],f[i+1][2]);//当i非绿,点数不加
            f[i][2]=max(f[i+1][0],f[i+1][1]);
            //同理
            ff[i][0]=min(ff[i+1][1],ff[i+1][2])+1;//当i为绿色,点数+1
            ff[i][1]=min(ff[i+1][0],ff[i+1][2]);//当i非绿,点数不加
            ff[i][2]=min(ff[i+1][0],ff[i+1][1]);
        }else{//i有两个儿子
            int k = ++now;//右儿子肯定不和父亲相邻,now此时为上一次dfs左儿子时得到的最后一个叶子结点,++now就到了右儿子上
            dfs(k);//这里不可直接dfs(++now),因为在dfs右儿子的过程中now会被更改.而我们下面是要用原来右儿子的值去改i的值,所以要用k记录下右儿子编号
            f[i][0] =max(f[i+1][1]+f[k][2],f[i+1][2]+f[k][1])+1;//分情况讨论
            f[i][1]=max(f[i+1][0]+f[k][2],f[i+1][2]+f[k][0]);
            f[i][2]=max(f[i+1][0]+f[k][1],f[i+1][1]+f[k][0]);
            
            ff[i][0]=min(ff[i+1][1]+ff[k][2],ff[i+1][2]+ff[k][1])+1;
            ff[i][1]=min(ff[i+1][0]+ff[k][2],ff[i+1][2]+ff[k][0]);
            ff[i][2]=min(ff[i+1][0]+ff[k][1],ff[i+1][1]+ff[k][0]);
        }
        //ans=max(ans,f[i][0]);
    }
    
    int main(){
        scanf("%s",a+1);
        dfs(++now);
        ans=max(max(f[1][0],f[1][1]),f[1][2]);
        anss=min(min(ff[1][0],ff[1][1]),ff[1][2]);
        printf("%d %d",ans,anss);
        return 0;
    }
     
  • 相关阅读:
    【Delphi】MD5算法(二):应用
    迅雷不能下载FlashPlayer,下载后自动删除,狂汗!!!
    工作笔记1
    GridControl 获取筛选后的数据{笔记}
    Invoke与BeginInvoke[转]
    这几项能力不知道要几年
    你永远不要去做的事1【译】
    window环境变量——心得【转】
    刚做好的网站客服系统,欢迎大家测试
    .Net 2.0里有一个有用的新功能:迭代器
  • 原文地址:https://www.cnblogs.com/Siegfried-L/p/12986877.html
Copyright © 2020-2023  润新知