[BZOJ1864][CODEVS2462]三色二叉树

题目描述 Description

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

       |-0  表示该树没有子节点

S = |-1S1 表示该树有一个子节点,S1为其子树的二叉树排列

       |- 2S1S2 表示该树有连个个子节点,S1、S2为其子树的二叉树排列

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

1122002010

样例输出 Sample Output

5 2

数据范围及提示 Data Size & Hint

 

之前的一些废话:准备期末复习。

题解:

f(i,0)表示这个点不为绿色
0个儿子:0
1个儿子:max(f(s,1),f(s,0))
2个儿子:max(f(s1,1)+f(s2,0),f(s1,0)+f(s2,2))

f(i,1)表示这个点为绿色
0个儿子:1
一个儿子:f(s,0)+1
两个儿子:f(s1,0)+f(s2,0)+1

g(i,0)表示这个点不为绿色
0个儿子:0
1个儿子:min(g(s,1),g(s,0))
2个儿子:min(g(s1,1)+g(s2,0),g(s1,0)+g(s2,2))

f(i,1)表示这个点为绿色
0个儿子:1
一个儿子:g(s,0)+1
两个儿子:g(s1,0)+g(s2,0)+1

然后把输入转化成一颗树的话。。下面代码已经写了。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define mem(a,b) memset(a,b,sizeof(a))
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int maxn=500010;
char s[maxn];
int len,tot=1,f[2][maxn],g[2][maxn],l[maxn],r[maxn];
void DP(int now)
{
    if(tot>len)return;
    f[1][now]=1;g[1][now]=1;
    if(s[now]=='0')return;
    if(s[now]=='1')
    {
        tot++;l[now]=tot;DP(tot);
        f[0][now]+=max(f[0][l[now]],f[1][l[now]]);
        f[1][now]+=f[0][l[now]];
        g[0][now]+=min(g[0][l[now]],g[1][l[now]]);
        g[1][now]+=g[0][l[now]];
    }
    if(s[now]=='2')
    {
        tot++;l[now]=tot;DP(tot);
        tot++;r[now]=tot;DP(tot);
        f[0][now]+=max(f[1][l[now]]+f[0][r[now]],f[0][l[now]]+f[1][r[now]]);
        f[1][now]+=f[0][l[now]]+f[0][r[now]];
        g[0][now]+=min(g[1][l[now]]+g[0][r[now]],g[0][l[now]]+g[1][r[now]]);
        g[1][now]+=g[0][l[now]]+g[0][r[now]];
    }
}
int main()
{
    scanf("%s",s+1);
    len=strlen(s+1);
    DP(1);
    printf("%d %d\n",max(f[0][1],f[1][1]),min(g[0][1],g[0][1]));
    return 0;
}
View Code

总结:

posted @ 2017-06-28 17:44  小飞淙的云端  阅读(173)  评论(0编辑  收藏  举报