AC通道:http://codevs.cn/problem/2462/
[分析]
一看,就知道这是一个基本的树形动规题。
设f[i][j]表示i节点颜色为j时,以它为根节点的二叉树的绿色节点的数量的最大值。
记lchild为i的左儿子,rchild为i的右儿子,很容易得到,
要求最小值也同理。
下面我给出复杂版的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct Node{
int lchild,rchild;
Node(){lchild=rchild=-1;}
};
int cnt=1,K=-1;
char s[500100];
Node l[500100];
int f1[500100][10];
int f2[501000][10];
inline int Max(int x,int y){
return x>y?x:y;
}
inline int Min(int x,int y){
return x<y?x:y;
}
void make(int now){
K++;
if(s[K]=='0'){
l[now].lchild=l[now].rchild=-1;
return;
}
if(s[K]=='1'){
l[now].lchild=++cnt;
l[now].rchild=-1;
make(cnt);
return;
}
l[now].lchild=++cnt;
make(cnt);
l[now].rchild=++cnt;
make(cnt);
}
#define lson l[now].lchild
#define rson l[now].rchild
void dfs(int now){
if(now==-1)return;
dfs(rson);
dfs(lson);
if(lson==-1&&rson==-1){
f1[now][1]=1,f1[now][2]=0,f1[now][3]=0;
f2[now][1]=1,f2[now][2]=0,f2[now][3]=0;
}
else if(lson!=-1&&rson==-1){
f1[now][1]=Max(f1[lson][2],f1[lson][3])+1;
f1[now][2]=Max(f1[lson][1],f1[lson][3]);
f1[now][3]=Max(f1[lson][1],f1[lson][2]);
f2[now][1]=Min(f2[lson][2],f2[lson][3])+1;
f2[now][2]=Min(f2[lson][1],f2[lson][3]);
f2[now][3]=Min(f2[lson][1],f2[lson][2]);
}
else if(lson!=-1&&rson!=-1){
f1[now][1]=Max(f1[lson][2]+f1[rson][3],f1[lson][3]+f1[rson][2])+1;
f1[now][2]=Max(f1[lson][1]+f1[rson][3],f1[lson][3]+f1[rson][1]);
f1[now][3]=Max(f1[lson][1]+f1[rson][2],f1[lson][2]+f1[rson][1]);
f2[now][1]=Min(f2[lson][2]+f2[rson][3],f2[lson][3]+f2[rson][2])+1;
f2[now][2]=Min(f2[lson][1]+f2[rson][3],f2[lson][3]+f2[rson][1]);
f2[now][3]=Min(f2[lson][1]+f2[rson][2],f2[lson][2]+f2[rson][1]);
}
}
int main(){
freopen("tro.in","r",stdin);
freopen("tro.out","w",stdout);
memset(f2,125/2,sizeof f2);
memset(f1,-1,sizeof f1);
scanf("%s",s);
make(1);
dfs(1);
printf("%d %d",Max(Max(f1[1][1],f1[1][2]),f1[1][3]),Min(Min(f2[1][1],f2[1][2]),f2[1][3]));
return 0;
}