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

一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:

例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。

你的任务是要对一棵二叉树的节点进行染色。每个节点可以被染成红色、绿色或蓝色。并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。

输入输出格式

输入数据由多组数据组成。
每组数据仅有一行,不超过10000个字符,表示一个二叉树序列。

对于每组输入数据,输出仅一行包含两个整数,依次表示最多和最少有多少个点能够被染成绿色。

样例输入

1122002010

样例输出

5 2



用dp[x][0/1/2]和f[x][0/1/2]分别记录x节点为绿/红/蓝的最多/最少的绿色节点数
这样就可以树形dp了


代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
char c[maxn];
int dp[maxn][3],f[maxn][3],cnt,ans=1;
void dfs(int x)
{
    if(c[x]=='0')
    {
        f[x][0]=dp[x][0]=1;
        return;
    }
    dfs(++cnt);
    if(c[x]=='1')
    {
        dp[x][0]=max(dp[x+1][1],dp[x+1][2])+1;
        dp[x][1]=max(dp[x+1][0],dp[x+1][2]);
        dp[x][2]=max(dp[x+1][0],dp[x+1][1]);
        f[x][0]=min(f[x+1][1],f[x+1][2])+1;
        f[x][1]=min(f[x+1][0],f[x+1][2]);
        f[x][2]=min(f[x+1][0],f[x+1][1]);
    }
    else 
    {
        int r=++cnt;
        dfs(r);
        dp[x][0]=max(dp[x+1][1]+dp[r][2],dp[x+1][2]+dp[r][1])+1;
        dp[x][1]=max(dp[x+1][0]+dp[r][2],dp[x+1][2]+dp[r][0]);
        dp[x][2]=max(dp[x+1][0]+dp[r][1],dp[x+1][1]+dp[r][0]);
        f[x][0]=min(f[x+1][1]+f[r][2],f[x+1][2]+f[r][1])+1;
        f[x][1]=min(f[x+1][0]+f[r][2],f[x+1][2]+f[r][0]);
        f[x][2]=min(f[x+1][0]+f[r][1],f[x+1][1]+f[r][0]);        
    }
    ans=max(ans,dp[x][0]);
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%s",c+1);
    dfs(++cnt);
    printf("%d ",ans);
    printf("%d",min(f[1][0],min(f[1][2],f[1][1])));
    return 0;
}

 

 
posted @ 2020-11-30 20:52  andyc_03  阅读(69)  评论(0编辑  收藏  举报