P2585 [ZJOI2006]三色二叉树
题目描述
输入输出格式
输入格式:
输入文件名:TRO.IN
输入文件仅有一行,不超过10000个字符,表示一个二叉树序列。
输出格式:
输出文件名:TRO.OUT
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
输入输出样例
输入样例#1:
1122002010
输出样例#1:
5 2
思路:
我们只关心绿色节点的数目,而红色蓝色可以看作无色,
但是对于一个根节点和它的两个儿子,必须有一个绿色节点
按照树形DP的思路,我们开一个二维数组dp[Maxn][2]
一二维分别保存:
该树的最优数目,该根节点涂绿色与不涂绿色[1表示涂绿色,0表示不涂]
以最大绿色数为例:
dp[i][0]=max(dp[left[i]][1]+dp[right[i]][0],dp[left[i]][0]+dp[right[i]][1]);
如果不涂i节点, 那么i节点的子节点一定要有一个涂, 所以要么左为1右为0, 要么左为0右为1
即:
dp[i][1]=dp[left[i]][0]+dp[right[i]][0]+1
如果涂i节点,那么它的两个儿子当然都不能涂! [别忘了还需要加上1,即:统计上i节点的绿色]
最小绿色也是一个道理,只要把max改为min即可:
dp[i][0]=min(dp[left[i]][1]+dp[right[i]][0],dp[left[i]][0]+dp[right[i]][1]);
坑点:
数据范围是个大坑....应该开到10万才可以,他少打了个0....
上代码:
/* Max dp[i][1]=dp[left[i]][0]+dp[right[i]][0]+1 Min dp[i][0]=min(dp[left[i]][1]+dp[right[i]][0],dp[left[i]][0]+dp[right[i]][1]); */ #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int Maxn = 1000010; const int Colors = 2; int rt,top=0; int L[Maxn],R[Maxn]; ///第一维表示第几个点,第二维表示染什么颜色 int dpMax[Maxn][Colors],dpMin[Maxn][Colors]; int Max(int a, int b) {return a > b ? a : b;} int Min(int a, int b) {return a < b ? a : b;} int build() { top++; int num=top; int son=getchar()-'0'; ///默认为son==0时没有孩子,son==1时只有左孩子,son==2时左右均有. if(son==0) { L[num]=0; R[num]=0; } else if(son==1) { L[num]=build(); R[num]=0; } else { L[num]=build(); R[num]=build(); } ///返回孩子编号 return num; } ///找较大值 void findMax(int u) { if(dpMax[L[u]][0]==-1) findMax(L[u]); if(dpMax[R[u]][0]==-1) findMax(R[u]); dpMax[u][0]=Max(dpMax[L[u]][0]+dpMax[R[u]][1],dpMax[L[u]][1]+dpMax[R[u]][0]); dpMax[u][1]=dpMax[L[u]][0]+dpMax[R[u]][0]+1; } ///找较小值 void findMin(int u) { if(dpMin[L[u]][0]==-1) findMin(L[u]); if(dpMin[R[u]][0]==-1) findMin(R[u]); dpMin[u][0]=Min(dpMin[L[u]][0]+dpMin[R[u]][1],dpMin[L[u]][1]+dpMin[R[u]][0]); dpMin[u][1]=dpMin[L[u]][0]+dpMin[R[u]][0]+1; } int main() { rt=build(); memset(dpMax,-1,sizeof(dpMax)); memset(dpMin,-1,sizeof(dpMin)); ///空节点为0,便于更新 dpMax[0][1]=dpMax[0][0]=0; dpMin[0][1]=dpMin[0][0]=0; findMax(rt); findMin(rt); int a1=Max(dpMax[rt][0],dpMax[rt][1]), a2=Min(dpMin[rt][0],dpMin[rt][1]); printf("%d %d",a1,a2); return 0; }