zoukankan      html  css  js  c++  java
  • 三色二叉树 ---伪树形dp

    题目描述

    一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:

    0 该树没有子节点 1S1 该树有一个子节点,S1为其二叉树序列 1S1S2 该树有两个子节点,S1,S2分别为两个二叉树的序列 例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。

    你的任务是要对一棵二叉树的节点进行染色。每个节点可以被染成红色、绿色或蓝色。并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。

    题目大意:

    给你一棵树,相邻点不同色,共三色,求一种颜色最多最少涂法。
    分析:

    根据题目条件列转移方程:

    性质1.因为有三种颜色,所以如果父节点不是绿,那么两儿子必有一个是绿。(废话1)

    性质2.如果父节点是绿,而两个子节点必然都不绿,且不冲突。(废话2)

    我们不妨设置两种情况(新开一维度):dp[ rt ][ 0 ]表示 rt这个点不是绿色,dp[ rt ][ 1 ]表示是绿色,dp数组的值表示以这个点为根节点的树最多涂几个绿点。
    我们可以给每一个节点设置初始值:dp[ rt ][ 0 ]=0,dp[ rt ][ 1 ]=1(很好理解吧。。。)

    转移方程:1. dp[ rt ][ 1]=dp[ lch[ rt ] ] [ 0 ]+dp[ rch[ rt ] ] [ 0 ]+1;

          该点涂绿情况:左儿子不涂绿情况+右儿子不涂绿情况+自己;

          (如果这个点涂成绿色,那么左右两点都不可以涂成绿色,且这样的左右两点不冲突情况必定存在,即性质2)

         2.dp[ rt ][ 0 ]=min/max ( dp[ lch[ rt ] ] [ 0 ]+dp[ rch[ rt ] ] [ 1 ]  ,  dp[ lch[ rt ] ] [ 1]+dp[ rch[ rt ] ] [ 0 ] );

          该点不涂绿情况:左儿子不涂绿,右儿子涂绿或者左儿子涂绿,右儿子不涂绿。

          (也是必然条件,符合上面性质1)

    然后就是dfs了

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=1e6+10;
    char s[maxn];int a[maxn];
    int cnt=1;//用来确定dfs序,因为1是根了,所以已经有一个了(废话) int lch[maxn],rch[maxn],dp[maxn][2];
    void build(int rt){//递归建树,自行理解,代码不唯一 
        if(a[rt]==1){
            lch[rt]=++cnt;    
            build(lch[rt]);
        }else if(a[rt]==2){
            lch[rt]=++cnt;    
            build(lch[rt]);
            rch[rt]=++cnt;
            build(rch[rt]);
        }else if(a[rt]==0){
            return;
        }
    }
    void dfsmax(int rt){
        dp[rt][1]=1;dp[rt][0]=0;
        if(lch[rt])dfsmax(lch[rt]);
        if(rch[rt])dfsmax(rch[rt]);
        dp[rt][1]=1+dp[lch[rt]][0]+dp[rch[rt]][0];
        dp[rt][0]=max(dp[lch[rt]][1]+dp[rch[rt]][0],dp[lch[rt]][0]+dp[rch[rt]][1]);
        //转移方程 
    }
    void dfsmin(int x){
        dp[x][1]=1;dp[x][0]=0;
        if(lch[x]) dfsmin(lch[x]);
        if(rch[x]) dfsmin(rch[x]);
        dp[x][1]=1+dp[lch[x]][0]+dp[rch[x]][0];
        dp[x][0]=min(dp[lch[x]][1]+dp[rch[x]][0],dp[lch[x]][0]+dp[rch[x]][1]);
    }
    int main(){
        scanf("%s",s);
        int len=strlen(s);
        for(int i=0;i<len;i++){
            a[i+1]=s[i]-'0';//字符数组转整形,可忽略 
        }
        build(1);
        dfsmax(1);//以1为根节点建树并进行下列操作 
        printf("%d ",max(dp[1][1],dp[1][0]));//根节点里面保存的就是整个树的情况了 
        memset(dp,0,sizeof(dp));//记得初始化!!! 
        dfsmin(1);
        printf("%d ",min(dp[1][1],dp[1][0]));
        return 0;
    }
  • 相关阅读:
    《构建之法阅读笔记02》
    《人月神话阅读笔记01》
    第四周学习进度条
    子数组2
    敏捷开发方法综述
    子数组1
    第三周学习进度条
    四则运算3
    第二周学习进度条
    四则运算4
  • 原文地址:https://www.cnblogs.com/liu-yi-tong/p/12984192.html
Copyright © 2011-2022 走看看