【BZOJ】 水题 1864 三色二叉树

BZOJ  1864  三色二叉树

 

直观感受比较难,因为之前的一道树上染色就把我惊住了,想了好久。

 

先一步步解决问题,读入就是一个困难—— 如何解决将表达串转化为树呢?

 

发现不论是“1 S1”还是“2 S1 S2”来说都是有左子树的,并且观察样例可以知道,左子树处理完了以后才处理右子树。所以可以递归建树,由于是二叉树,只需要用ls和rs数组存左右儿子就好了。

 

那么如何求染成绿色的最大值呢?想到DP。因为只需要染一种颜色,那么我们只需要关注这个点是不是被染成绿色就好了!

 

定义状态dp ( u,0/1):

 

dp( u,1)表示这个点被染成绿色,那么子树一定是其他颜色,注意不需要管儿子被染成什么颜色了;所以得到转移方程1:

dp(u,1)= dp(ls ( u),0)+ dp(rs ( u),0)+ 1;

 

dp ( u,0)表示这个点没有被染成绿色,那么子树一定有一个被染成绿色了,另一个被染成其他颜色了,只是我们不知道到底哪一个被染成了什么颜色;不用担心,因为只会有两种情况,要么左儿子被染成绿色,要么右儿子被染成绿色,我们只需要对这两个情况取最小值(或最大值(根据需要求染绿色的最值决定))所以得到转移方程2:

                                     dp(ls (u),1)+ dp(rs ( u),0) <- 左儿子绿色,右儿子其他色

dp(u,0) min/max

                                     dp(ls (u),0)+ dp(rs ( u),1) <- 右儿子绿色,左儿子其他色

 

代码:


/**************************************************************
    Problem: 1864
    User: jerrywans
    Language: C++
    Result: Accepted
    Time:328 ms
    Memory:29028 kb
****************************************************************/
 
#include <bits/stdc++.h>
 
const  int  N = 500000 + 5 ; 
 
int  dp [ N << 2 ] [ 3 ] , ls [ N ] , rs [ N ] ;
int  tail = 1 ;
 
int  minx ( int  a , int  b ) {
    return  a < b ? a : b ; 
}
 
int  maxx ( int  a , int  b ) {
    return  a > b ? a : b ; 
}
 
void  build ( int  x ) {
    char  c ;
    scanf ( "%c" , &c ) ;
    if ( c == '0' )  return ;
    ls [ x ] = ++ tail ;
    build ( ls [ x ] ) ;
    if ( c == '2' ) {
        rs [ x ] = ++ tail ;
        build ( rs [ x ] ) ;
    }
}
 
void  dfs ( int  u , int  opt ) {
    if ( !u )  return  ;
    dfs ( ls [ u ] , opt ) ;
    dfs ( rs [ u ] , opt ) ;
     
    dp [ u ] [ 1 ] = dp [ ls [ u ] ] [ 0 ] + dp [ rs [ u ] ] [ 0 ] + 1 ; 
    if ( opt == 1 )
        dp [ u ] [ 0 ] = maxx ( dp [ ls [ u ] ] [ 1 ] + dp [ rs [ u ] ] [ 0 ] , dp [ ls [ u ] ] [ 0 ] + dp [ rs [ u ] ] [ 1 ] ) ;
    else
        dp [ u ] [ 0 ] = minx ( dp [ ls [ u ] ] [ 1 ] + dp [ rs [ u ] ] [ 0 ] , dp [ ls [ u ] ] [ 0 ] + dp [ rs [ u ] ] [ 1 ] ) ;
}
 
int  main ( ) {
    build ( 1 ) ;
    dfs ( 1 , 1 ) ;
    printf ( "%d " , maxx ( dp [ 1 ] [ 0 ] , dp [ 1 ] [ 1 ] ) ) ;
    memset ( dp , 0 , sizeof ( dp ) ) ;
    dfs ( 1 , 2 ) ;
    printf ( "%d" , minx ( dp [ 1 ] [ 0 ] , dp [ 1 ] [ 1 ] ) ) ;
     
    return  0 ;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值