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

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

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

亮出15CM-->

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

#include 
#include 
#include 
#include 

/*
	树形dp,定义状态dp[i][j]表示结点i颜色为j(下面枚举对应,记0为绿色) 时可以搞到
	的最大答案
	转移:
		dp[father][0] = max{dp[leftson][1]+1, dp[leftson][2]+1};
		dp[father][1] = max{dp[leftson][0], dp[leftson][2]};
		dp[father[2] = max{dp[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
*/


你可能感兴趣的:(水题,动态规划)