[FZU 1022] 三色二叉树/二叉树染色

Posted bit_line

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[FZU 1022] 三色二叉树/二叉树染色相关的知识,希望对你有一定的参考价值。

模拟题,当然也可以叫树形dp。

数据结构作业,所以要写一棵树,为了可读性,又手残枚举了三种颜色,所以代码显得长一些,但是整个的思路还是非常的好理解的。而且变量名也尽量取得即使长一些也是很好理解的,呵呵...

亮出15CM-->

/*
	链接http://acm.fzu.edu.cn/problem.php?pid=1022
	187 ms 	2180KB
*/
/*********by JBer********/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>

/*
	树形dp,定义状态dp[i][j]表示结点i颜色为j(下面枚举对应,记0为绿色) 时可以搞到
	的最大答案
	转移:
		dp[father][0] = maxdp[leftson][1]+1, dp[leftson][2]+1;
		dp[father][1] = maxdp[leftson][0], dp[leftson][2];
		dp[father[2] = maxdp[leftson][0], dp[leftson][1];
			---当father只有左孩纸时
		其它情况类似
	初始化孩纸们的dp[][0] = 1, dp[][1] = dp[][2] = 0就可以搞了= = 
*/

const int COLORTYPE = 3;
enum COLOR GREEN, RED, BLUE, NONE;

struct Node 
	Node* left, *right;
	int maxGreen[COLORTYPE];	//maxGreen[i]该结点颜色为i时可以搞出的最大绿色结点数目 
	int minGreen[COLORTYPE];	//和上面差不多= = 
	//int tag[COLORTYPE];
	Node() 
		left = right = NULL;
		memset(maxGreen, 0, sizeof(int) * COLORTYPE);
		memset(minGreen, 0, sizeof(int) * COLORTYPE);
		//memset(tag, -1, sizeof(int) * COLORTYPE);
	
;
typedef Node* binTree;

char* build(binTree& T, char* s) 
	//printf("%c->%d\\n", *s, s);
	if (s[0] == '0') 
		T = new Node();
		return s + 1;
	 else if (s[0] == '1') 
		T = new Node();
		return build(T->left, s + 1);
	 else 
		T = new Node();
		char* p = build(T->left, s + 1);
		return build(T->right, p);
	


int countNode(const binTree& T) 
	if (T == NULL) 
	//	puts("0");
		return 0;
	
	//printf("T->left = %d, T->right = %d\\n", T->left ? 1 : 0, T->right ? 1 : 0);
	return countNode(T->left) + countNode(T->right) + 1;


void Destroy(binTree& T) 
	if (T == NULL) return;
	Destroy(T->left);
	Destroy(T->right);
	delete T;


void treeDP(const binTree& T) 
	if (T == NULL) return;
	treeDP(T->left);
	treeDP(T->right);
	if (T->left == NULL && T->right == NULL) 
		T->maxGreen[GREEN] = 1, T->maxGreen[RED] = T->maxGreen[BLUE] = 0;
		T->minGreen[GREEN] = 1, T->minGreen[RED] = T->minGreen[BLUE] = 0;
	 else if (T->left != NULL && T->right == NULL) 
		T->maxGreen[GREEN] = std::max(T->left->maxGreen[RED], T->left->maxGreen[BLUE]) + 1;
		T->maxGreen[RED] = std::max(T->left->maxGreen[GREEN], T->left->maxGreen[BLUE]);
		T->maxGreen[BLUE] = std::max(T->left->maxGreen[GREEN], T->left->maxGreen[RED]);
		
		T->minGreen[GREEN] = std::min(T->left->minGreen[RED], T->left->minGreen[BLUE]) + 1;
		T->minGreen[RED] = std::min(T->left->minGreen[GREEN], T->left->minGreen[BLUE]);
		T->minGreen[BLUE] = std::min(T->left->minGreen[GREEN], T->left->minGreen[RED]);
	 else if (T->left == NULL && T->right != NULL) 
		T->maxGreen[GREEN] = std::max(T->right->maxGreen[RED], T->right->maxGreen[BLUE]) + 1;
		T->maxGreen[RED] = std::max(T->right->maxGreen[GREEN], T->right->maxGreen[BLUE]);
		T->maxGreen[BLUE] = std::max(T->right->maxGreen[GREEN], T->right->maxGreen[RED]);
		
		T->minGreen[GREEN] = std::min(T->right->minGreen[RED], T->right->minGreen[BLUE]) + 1;
		T->minGreen[RED] = std::min(T->right->minGreen[GREEN], T->right->minGreen[BLUE]);
		T->minGreen[BLUE] = std::min(T->right->minGreen[GREEN], T->right->minGreen[RED]);
	 else 
		//equal to: T->left != NULL && T->right != NULL
		//这里有一个trick,所以搞起来要注意两个子节点颜色不同的要求,转移方程作适当变化
		T->maxGreen[GREEN] = std::max(T->left->maxGreen[RED] + T->right->maxGreen[BLUE], T->left->maxGreen[BLUE] + T->right->maxGreen[RED]) + 1;
		T->maxGreen[RED] = std::max(T->left->maxGreen[GREEN] + T->right->maxGreen[BLUE], T->left->maxGreen[BLUE] + T->right->maxGreen[GREEN]);
		T->maxGreen[BLUE] = std::max(T->left->maxGreen[GREEN] + T->right->maxGreen[RED], T->left->maxGreen[RED] + T->right->maxGreen[GREEN]);
		
		T->minGreen[GREEN] = std::min(T->left->minGreen[RED] + T->right->minGreen[BLUE], T->left->minGreen[BLUE] + T->right->minGreen[RED]) + 1;
		T->minGreen[RED] = std::min(T->left->minGreen[GREEN] + T->right->minGreen[BLUE], T->left->minGreen[BLUE] + T->right->minGreen[GREEN]);
		T->minGreen[BLUE] = std::min(T->left->minGreen[GREEN] + T->right->minGreen[RED], T->left->minGreen[RED] + T->right->minGreen[GREEN]);
	
	/*
	int maxTmp = -1;
	for (int i = 0; i < COLORTYPE; ++i) 
		if (T->maxGreen[i] > maxTmp) maxTmp = T->maxGreen[i];
	
	printf("%d\\n", maxTmp);
	*/


const int MAXLEN = 10086;
char buffer[MAXLEN];

int main() 
	while (~scanf(" %s", buffer)) 
		binTree T = NULL;
		build(T, buffer);

		//printf("%d\\n", countNode(T));
		treeDP(T);

		int minAns = INT_MAX, maxAns = INT_MIN;
		for (int i = 0; i < COLORTYPE; ++i) 
			if (T->maxGreen[i] > maxAns) maxAns = T->maxGreen[i];
			if (T->minGreen[i] < minAns) minAns = T->minGreen[i];
		
		printf("%d %d\\n", maxAns, minAns);
		Destroy(T);
	

	return 0;

/*
1122002010
5 2
*/


以上是关于[FZU 1022] 三色二叉树/二叉树染色的主要内容,如果未能解决你的问题,请参考以下文章

树形DP三色二叉树

题解 bzoj1864: [Zjoi2006]三色二叉树 (动态规划)

[ZJOI2006] 三色二叉树

ZJOI2016 三色二叉树

[ZJOI2006] 三色二叉树

bzoj1864 三色二叉树