zoukankan      html  css  js  c++  java
  • 【bzoj1864】[ZJOI2006]三色二叉树 树形dp

    题目描述

    输入

    仅有一行,不超过500000个字符,表示一个二叉树序列。

    输出

    输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

    样例输入

    1122002010

    样例输出

    5 2


    题解

    比较简单的一道树形dp

    f[i]表示i为绿色时以i为根的子树中绿色节点的个数和,g[i]表示i不为绿色时以i为根的子树中绿色节点的个数和。

    由于这是一棵二叉树,很容易推出状态转移方程为f[i]=g[l[i]]+g[r[i]];g[i]=min/max(f[l[i]]+g[r[i]],g[l[i]]+f[r[i]])。

    注意空节点的处理

    #include <stdio.h>
    #include <string.h>
    int f[300001] , g[300001] , l[300001] , r[300001] , p , n;
    char str[500002];
    int min(int a , int b)
    {
        return a < b ? a : b;
    }
    int max(int a , int b)
    {
        return a > b ? a : b;
    }
    void init()
    {
        p ++ ;
        n ++ ;
        int now = n;
        if(str[p] == '2')
        {
            l[now] = n + 1;
            init();
            r[now] = n + 1;
            init();
        }
        else if(str[p] == '1')
        {
            l[now] = n + 1;
            init();
        }
    }
    void dpmax(int x)
    {
        if(!x)
            return;
        dpmax(l[x]);
        dpmax(r[x]);
        f[x] = g[l[x]] + g[r[x]] + 1;
        g[x] = max(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]);
    }
    void dpmin(int x)
    {
        if(!x)
            return;
        dpmin(l[x]);
        dpmin(r[x]);
        f[x] = g[l[x]] + g[r[x]] + 1;
        g[x] = min(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]);
    }
    int main()
    {
        scanf("%s" , str + 1);
        init();
        dpmax(1);
        printf("%d " , max(f[1] , g[1]));
        memset(f , 0 , sizeof(f));
        memset(g , 0 , sizeof(g));
        dpmin(1);
        printf("%d
    " , min(f[1] , g[1]));
        return 0;
    }
  • 相关阅读:
    字典常用操作复习
    列表常用方法复习
    爬虫流程复习
    协程解决素数
    yield 复习
    多线程复习2
    多线程复习1
    异常 巩固3
    logging日志基础示例
    2019最新百度网盘不限速下载教程
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6151488.html
Copyright © 2011-2022 走看看