zoukankan      html  css  js  c++  java
  • 【树形DP】洛谷P2585 [ZJOI2006] 三色二叉树

    【树形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]);
    }
    
    
  • 相关阅读:
    关于 php json float 出现很多位的问题
    做 Excel 的 XML schema.xsd
    笔记:Python 默认参数必须指向不变对象
    Bartender 使用 Excel xlsx 数据库时出现 0x800A0E7A
    Javascript 中 的 for ... in 和 for ... of 差别
    关于跨域资料收集 (2019-01-11)
    ThinkPHP3 和 ThinkPHP5 不是一个团队做的
    记录一下:给电推剪改锂电池
    为你的Web程序加个启动画面
    前端不为人知的一面--前端冷知识集锦 前端已经被玩儿坏了!像console.log()可以向控制台输出图片
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/12983198.html
Copyright © 2011-2022 走看看