三色二叉树——树形dp

三色二叉树

题目描述

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

\(0\) 该树没有子节点。
\(1S_1\) 该树有一个子节点。
\(S_1\) 为其二叉树序列 \(1S_1S_2\) 该树有两个子节点,\(S_1,S_2\) 分别为两个二叉树的序列 例如,下图所表示的二叉树可以用二叉树序列 \(S=21200110\) 来表示。

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

输入格式

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

输出格式

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

样例

样例输入

1122002010

样例输出

5 2

题目大意

给你一个二叉树的前序遍历,然后对每个节点进行染色,可以染成红色、绿色或蓝色,来求出这颗二叉树中最多、最少有多少个点能被染成绿色。

基本思路

将每个节点挨个遍历,

若它的子节点数为0:

则只有两种选择:染绿和不染绿。

若它的子节点数为1:

则可以它染绿,儿子不染绿,加上1就可以;

可以它不染绿,儿子既可以染绿,又可以不染绿,取最大值/最小值即可。

若它的子节点数为2:

则可以它染绿,两个儿子都不染绿,加上 \(1\) 就可以;

可以它不染绿,可以左儿子染绿右儿子不染绿,也可以左儿子不染绿右儿子染绿,取最大值/最小值即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+50,INF=0x3f3f3f3f;
char s[maxn];
int n;
int f[maxn][2];//f[i][0]表示染绿,f[i][1]表示不染绿 
int tree[maxn];//整个树的数组 
int lz[maxn],rz[maxn];//左儿子,右儿子 
int Find(int x){//建树 
	if(tree[x])return tree[x];
	if(s[x]=='0'){
		tree[x]=x;
	}else{
		if(s[x]=='1'){
			tree[x]=Find(x+1);
		}else{
			tree[x]=Find(Find(x+1)+1);
		}
	}
	return tree[x];
}
void dfs1(int x){//求最大值 
	if(f[x][0]) return;
	if(s[x]=='0'){//没有子节点 
		f[x][0]=1;
		f[x][1]=0;
	}else{
		if(s[x]=='1'){//有一个子节点 
			dfs1(lz[x]);
			f[x][0]=f[lz[x]][1]+1;
			f[x][1]=max(f[lz[x]][1],f[lz[x]][0]);
		}else{//有两个子节点 
			dfs1(lz[x]);
			dfs1(rz[x]);
			f[x][0]=f[lz[x]][1]+f[rz[x]][1]+1;
			f[x][1]=max(f[lz[x]][1]+f[rz[x]][0],f[lz[x]][0]+f[rz[x]][1]);
		}
	}
}
void dfs2(int x){//求最小值 
	if(f[x][0]<INF){
		return;
	}
	if(s[x]=='0'){//没有子节点
		f[x][0]=1;
		f[x][1]=0;
	}else{
		if(s[x]=='1'){//有一个子节点
			dfs2(lz[x]);
			f[x][0]=f[lz[x]][1]+1;
			f[x][1]=min(f[lz[x]][1],f[lz[x]][0]);
		}else{//有两个子节点
			dfs2(lz[x]);
			dfs2(rz[x]);
			f[x][0]=f[lz[x]][1]+f[rz[x]][1]+1;
			f[x][1]=min(f[lz[x]][1]+f[rz[x]][0],f[lz[x]][0]+f[rz[x]][1]);
		}
	}
}
int main(){
	scanf("%s",s);
	n=strlen(s);
	Find(0);//使整个数组得以保存 
	for(int i=0;i<n;i++){
		lz[i]=i+1;
		rz[i]=tree[lz[i]]+1;
	}
	dfs1(0);
	printf("%d ",max(f[0][0],f[0][1]));
	for(int i=0;i<n;i++){//求最小值初始化为INF 
		f[i][0]=f[i][1]=INF;
	}
	dfs2(0);
	printf("%d\n",min(f[0][0],f[0][1]));
	return 0;
}
posted @ 2020-05-29 14:10  Rubyonlу  阅读(559)  评论(0编辑  收藏  举报