【树形DP】三色二叉树

标签(空格分隔): 树形DP


【题目】

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

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

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

输入格式

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

输出格式

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

样例输入

1122002010

样例输出

5 2

【思路】

(想是好想,调是真难调)

1.题目中又让输出最多又让输出最小的,一看就要开2个数组,一个存最大,一个存最小,f[u][]表示以u为根节点的最大绿节点,d[u][]表示以u为根节点的最小绿节点

2.每个节点可以是三种颜色中的一种,根据我们之前写过的小胖守皇宫和没有上司的舞会,很容易想到用三个状态分别表示三个颜色,这题我是以0做绿,1-红,2-蓝

3.建树是个头疼的问题,细细搞♂了搞题目,这个序列有一个显著特点:如果u有子节点,u+1一定是它的另一个子节点,而另一个节点却不一定是u+2(自己可以画个图,样例就是这样的),这里只能对整个树进行编号(DFS序),然后搞DFS序

4.各种转移情况看代码

【代码】

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e6+50,INF=0x3f3f3f3f;
int n,m,f[maxn][4],tot=1,d[maxn][4],b[maxn],ans=1;
char str[maxn];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;ch=getchar();
}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}//绿 红 蓝
// 0 1 2
void DFS(int u){
if(str[u]=='0'){
f[u][0]=d[u][0]=1;
return;
}
DFS(++tot);//递归一个子节点的
if(str[u]=='1'){//只有一个节点
f[u][0]=max(f[u+1][1],f[u+1][2])+1;//u被染绿了,那它的子节点一定不是绿色
f[u][1]=max(f[u+1][0],f[u+1][2]);//u被染红了,它的子节点一定不是红色
f[u][2]=max(f[u+1][1],f[u+1][0]);//以下同理
d[u][0]=min(d[u+1][1],d[u+1][2])+1;
d[u][1]=min(d[u+1][0],d[u+1][2]);
d[u][2]=min(d[u+1][1],d[u+1][0]);
}else if(str[u]=='2'){
int k=++tot;//这里由于建树的问题,如果u有子节点,那u+1一定是它的一个子节点,另一个节点就是k
DFS(k);//还有一个节点就递归那个节点
f[u][0]=max(f[u+1][1]+f[k][2],f[k][1]+f[u+1][2])+1;//u被染绿了,那它的两个子节点一定不是绿色,取红蓝和蓝红中最大的一个
f[u][1]=max(f[u+1][0]+f[k][2],f[k][0]+f[u+1][2]);//u被染红了,那它的两个子节点一定不是红色,取绿蓝和蓝绿中最大的一个
f[u][2]=max(f[u+1][1]+f[k][0],f[k][1]+f[u+1][0]);//以下同理
d[u][0]=min(d[u+1][1]+d[k][2],d[k][1]+d[u+1][2])+1;
d[u][1]=min(d[u+1][0]+d[k][2],d[k][0]+d[u+1][2]);
d[u][2]=min(d[u+1][1]+d[k][0],d[k][1]+d[u+1][0]);
}
ans=max(ans,f[u][0]);
return;
}
int main(){
freopen("a.in","r",stdin);
cin>>str+1;
DFS(1);
cout<<ans<<" "<<min(min(d[1][1],d[1][2]),d[1][0]);
}

【树形DP】洛谷P2585 [ZJOI2006] 三色二叉树的更多相关文章

  1. 洛谷P2585 [ZJOI2006]三色二叉树(树形dp)

    传送门 设$dp[u][i]$表示点$u$颜色为$i$时最多(最少)的绿点个数(这里用$0$表示绿点) 然后直接用树形dp就可以了 记得把情况讨论清楚 //minamoto #include<b ...

  2. 洛谷P2585 [ZJOI2006]三色二叉树

    题目描述 输入输出格式 输入格式: 输入文件名:TRO.IN 输入文件仅有一行,不超过10000个字符,表示一个二叉树序列. 输出格式: 输出文件名:TRO.OUT 输出文件也只有一行,包含两个数,依 ...

  3. 洛谷 2585 [ZJOI2006]三色二叉树——树形dp

    题目:https://www.luogu.org/problemnew/show/P2585 可以把不是绿色的记成一种.仔细一想不会有冲突.如果自己是绿色,孩子的不同颜色不会冲突:如果自己不是绿色,自 ...

  4. 【洛谷P2585】三色二叉树

    题目大意:给定一个二叉树,可以染红绿黄三种颜色,要求父节点和子节点的颜色不同,且如果一个节点有两个子节点,那么两个子节点之间的颜色也不同.求最多和最少有多少个节点会被染成绿色. 题解:加深了对二叉树的 ...

  5. luogu P2585 [ZJOI2006]三色二叉树

    P2585 [ZJOI2006]三色二叉树 题目描述 输入输出格式 输入格式: 输入文件名:TRO.IN 输入文件仅有一行,不超过10000个字符,表示一个二叉树序列. 输出格式: 输出文件名:TRO ...

  6. P2585 [ZJOI2006]三色二叉树

    题目描述 输入输出格式 输入格式: 输入文件名:TRO.IN 输入文件仅有一行,不超过500000个字符,表示一个二叉树序列. 输出格式: 输出文件名:TRO.OUT 输出文件也只有一行,包含两个数, ...

  7. 【BZOJ1864】[Zjoi2006]三色二叉树 树形DP

    1864: [Zjoi2006]三色二叉树 Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最 ...

  8. BZOJ_1864_[Zjoi2006]三色二叉树_树形DP

    BZOJ_1864_[Zjoi2006]三色二叉树_树形DP 题意: 分析:递归建树,然后DP,从子节点转移. 注意到红色和蓝色没有区别,因为我们可以将红蓝互换而方案是相同的.这样的话我们只需要知道当 ...

  9. BZOJ1864[ZJOI2006]三色二叉树[树形DP]

    1864: [Zjoi2006]三色二叉树 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 773  Solved: 548[Submit][Status] ...

随机推荐

  1. Git Gui工具从远程克隆代码总是提示路径已经存在。问题完美解决!

    最近使用Git Gui工具从远程克隆代码总是提示路径已经存在,提示如下图, 原因是使用Git Guii克隆代码时的路径不能是选择一个已经建好的目录(D盘的project下的test文件夹是我提前建好的 ...

  2. python3 驱动自动安装脚本

    from pywinauto.application import Applicationimport osimport timeos.system('start C:/Users/Administr ...

  3. hadoop启动后,9000端口无法连接,netstat -tpnl中找不到该端口

    已解决: 需要重新格式化hdfs. 1.停止hdfs: 2.删除hdfs的相关文件目录(hdfs-site.xml中配置的存放文件的目录). 3.启动journalnode:sbin/hadoop-d ...

  4. 我们为什么要用hibernate

    1.hibernate对JDBC访问数据库的代码做了一个封装,简化了数据访问繁琐的代码. 2.hibernate的性能非常好,因为它是个轻量级框架.映射的灵活性很好,它支持各种关系型数据库,从一对一到 ...

  5. Python 读取和输出到txt

    读txt文件 python常用的读取文件函数有三种read().readline().readlines() read() #一次性读取文本中全部的内容,以字符串的形式返回结果 with open(& ...

  6. Linux 和 Vim 常用命令整理

    Sftp常用命令: lcd f:本地切换到 F盘 lpwd本地 当前目录 lls本地 文件列表 put 本地 上传文件到服务器(put输入后,回车会有弹窗,选择上传文件) get下载文件到本地 Lin ...

  7. centos7.2挂载硬盘攻略

    远程SSH登录上CentOS服务器后,进行如下操作: 提醒:挂载操作会清空数据,请确认挂载盘无数据或者未使用 第一步:列出所有磁盘 命令: ll /dev/disk/by-path ll /dev/d ...

  8. Js中Array 函数使用方法

    遇到数组有关操作,脑子第一反应不要再是嵌套 for 循环了,Array 类型提供了一些遍历有关的函数. Array.prototype.forEach() : 把数组每个元素丢到一个处理 functi ...

  9. Chrome扩展移植到Edge浏览器教程

    微软在推出Edge浏览器之初,就把能够使用扩展(extension)作为一个重要功能.在Win10一周年更新版(1607)中,这项功能正式向广大用户推出(当然,Insider用户早就测试了一段时间了) ...

  10. [转] C++中的namespace

    点击阅读原文 namespace中文意思是命名空间或者叫名字空间,传统的C++只有一个全局的namespace,但是由于现在的程序的规模越来越大,程序的分工越来越细,全局作用域变得越来越拥挤,每个人都 ...