【bzoj1864】[ZJOI2006]三色二叉树 树形dp

题目描述

输入

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

输出

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

样例输入

1122002010

样例输出

5 2


题解

比较简单的一道树形dp

f[i]表示i为绿色时以i为根的子树中绿色节点的个数和,g[i]表示i不为绿色时以i为根的子树中绿色节点的个数和。

由于这是一棵二叉树,很容易推出状态转移方程为f[i]=g[l[i]]+g[r[i]];g[i]=min/max(f[l[i]]+g[r[i]],g[l[i]]+f[r[i]])。

注意空节点的处理

#include <stdio.h>
#include <string.h>
int f[300001] , g[300001] , l[300001] , r[300001] , p , n;
char str[500002];
int min(int a , int b)
{
    return a < b ? a : b;
}
int max(int a , int b)
{
    return a > b ? a : b;
}
void init()
{
    p ++ ;
    n ++ ;
    int now = n;
    if(str[p] == '2')
    {
        l[now] = n + 1;
        init();
        r[now] = n + 1;
        init();
    }
    else if(str[p] == '1')
    {
        l[now] = n + 1;
        init();
    }
}
void dpmax(int x)
{
    if(!x)
        return;
    dpmax(l[x]);
    dpmax(r[x]);
    f[x] = g[l[x]] + g[r[x]] + 1;
    g[x] = max(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]);
}
void dpmin(int x)
{
    if(!x)
        return;
    dpmin(l[x]);
    dpmin(r[x]);
    f[x] = g[l[x]] + g[r[x]] + 1;
    g[x] = min(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]);
}
int main()
{
    scanf("%s" , str + 1);
    init();
    dpmax(1);
    printf("%d " , max(f[1] , g[1]));
    memset(f , 0 , sizeof(f));
    memset(g , 0 , sizeof(g));
    dpmin(1);
    printf("%d\n" , min(f[1] , g[1]));
    return 0;
}
posted @ 2016-12-09 20:53  GXZlegend  阅读(327)  评论(0编辑  收藏  举报