打卡信奥刷题(2621)用C++实现信奥题 P2585 [ZJOI2006] 三色二叉树

P2585 [ZJOI2006] 三色二叉树

题目描述

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

S={0表示该树没有子节点1S1表示该树有一个节点,S1为其子树的二叉树序列2S1S2表示该树有两个子节点,S1和S2分别表示其两个子树的二叉树序列S= \begin{cases} 0& \text表示该树没有子节点\\ 1S_1& 表示该树有一个节点,S_1 为其子树的二叉树序列\\ 2S_1S_2& 表示该树有两个子节点,S_1 和 S_2 分别表示其两个子树的二叉树序列 \end{cases}S=01S12S1S2示该树没有子节点表示该树有一个节点,S1为其子树的二叉树序列表示该树有两个子节点,S1S2分别表示其两个子树的二叉树序列

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

haha.png

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

输入格式

输入只有一行一个字符串 sss,表示二叉树序列。

输出格式

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

输入输出样例 #1

输入 #1

1122002010

输出 #1

5 2

说明/提示

数据规模与约定

对于全部的测试点,保证 1≤∣s∣≤5×1051 \leq |s| \leq 5 \times 10^51s5×105sss 中只含字符 0 1 2

C++实现

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 500050;
char s[N];
int dp[N][4], f[N][4], cnt;
int ans1 = 1;
void dfs(int x) {
	if (s[x] == '0') {//叶节点
		f[x][0] = dp[x][0] = 1;
		return;
	}
	dfs(++cnt);
	if (s[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 k = ++cnt;
		dfs(k);
		dp[x][0] = max(dp[x+1][1] + dp[k][2], dp[x+1][2] + dp[k][1]) + 1;
		dp[x][1] = max(dp[x+1][0] + dp[k][2], dp[x+1][2] + dp[k][0]);
		dp[x][2] = max(dp[x+1][0] + dp[k][1], dp[x+1][1] + dp[k][0]);
		
		f[x][0] = min(f[x+1][1] + f[k][2], f[x+1][2] + f[k][1]) + 1;
		f[x][1] = min(f[x+1][0] + f[k][2], f[x+1][2] + f[k][0]);
		f[x][2] = min(f[x+1][0] + f[k][1], f[x+1][1] + f[k][0]);
	}
	ans1 = max(ans1, dp[x][0]);
}
int main() {
	scanf ("%s", s + 1);
	dfs(++cnt);
	cout << ans1 << ' ' << min(f[1][0], min(f[1][1], f[1][2])) << endl;
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值