luogu P2585 [ZJOI2006]三色二叉树

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;
}

 

posted @ 2017-08-14 21:02  夜雨声不烦  阅读(165)  评论(0编辑  收藏  举报