1007. Red-black Tree

1007. Red-black Tree

标签: 动态规划 树形结构


题目描述

There is a kind of binary tree named red-black tree in the data structure. It has the following 5 properties:

(1) Every node is either red or black.
(2) The root is black.
(3) All the leaves are NULL nodes and are colored black.
(4) Each red node must have 2 black descends (may be NULL).
(5) All simple paths from any node x to a descendant leaf have the same number of black nodes.

We call a non-NULL node an internal node. From property (5) we can define the black-height of a red-black tree as the number of nodes on the simple path from the root (excluding the root itself) to any NULL leaf (including the NULL leaf). And we can derive that a red-black tree with black height H has at least 2H-1 internal nodes.

Here comes the question: given a positive N, how many distinct red-black trees are there that consist of exactly N internal nodes?

Input Specification:

Each input file contains one test case which gives a positive integer N (<= 500).

Output Specification:

For each case, print in a line the number of distinct red-black tees with N internal nodes. Since the answer may be very large, output the remainder of it divided by 1000000007 please.

Sample Input:

5

Sample Output:

8

题解

题目大意:给你一颗含有n个节点的红黑树,问有多少种方案数。(如果不知道啥是红黑树,右转百度)

最开始我的想法用dfs+组合数学,因为必须满足高度相等,所以我枚举上一层高度含有多少个黑色和白色节点,用组合数计算,不过其实枚举了很多重复的状态,所以最后T了一个点。
正解是DP:
设f[0/1][i][j]表示高度为i含有j个节点,当前节点为黑色/白色。
其实状态建立好了,转移方程就很明显了:

//当前节点是黑色 
f[0][j][i] += f[0][k][i - 1] * f[0][j - k - 1][i - 1] % p;
f[0][j][i] += (f[0][k][i - 1] * f[1][j - k - 1][i - 1]) * 2 % p;
f[0][j][i] += f[1][k][i - 1] * f[1][j - k - 1][i - 1] % p;
f[0][j][i] %= p;
//红色 
f[1][j][i] += f[0][k][i] * f[0][j - k - 1][i] % p;
f[1][j][i] %= p;

代码

//DP版 
#include<bits/stdc++.h>
#define N 600
#define ll long long
#define p 1000000007
using namespace std;

ll n, h;
ll Log[N], f[2][N][N];

int main()
{
    scanf("%lld", &n);
    Log[1] = 0;
    for(int i = 2; i <= n; i ++) Log[i] = Log[i / 2] + 1;
    h = Log[n] + 2;
    f[0][1][2] = f[1][1][1] = f[0][0][1] = 1;
    for(int i = 2; i <= h; i ++)
        for(int j = 2; j <= n; j ++)
            for(int k = 0; k < j; k ++)
            {
                //当前节点是黑色 
                f[0][j][i] += f[0][k][i - 1] * f[0][j - k - 1][i - 1] % p;
                f[0][j][i] += (f[0][k][i - 1] * f[1][j - k - 1][i - 1]) * 2 % p;
                f[0][j][i] += f[1][k][i - 1] * f[1][j - k - 1][i - 1] % p;
                f[0][j][i] %= p;
                //红色 
                f[1][j][i] += f[0][k][i] * f[0][j - k - 1][i] % p;
                f[1][j][i] %= p;
            }
    ll ans = 0;
    for(int i = 1; i <= h; i ++) ans += f[0][n][i], ans %= p;
    printf("%lld", ans);        
    return 0;
}
//递归版 
#include<bits/stdc++.h>
#define N 1100
#define ll long long
#define p 1000000007
using namespace std;

int n, m;
ll ans = 0;
ll c[N][N], bin[N];

void pre()
{
    bin[0] = 1;
    for(int i = 1; i <= 20; i ++) 
        bin[i] = bin[i - 1] * 2;
    int t = 510;
    for(int i = 0; i <= t; i ++) 
        c[i][i] = c[i][0] = 1;
    for(int i = 1; i <= t; i ++)
        for(int j = 1; j < i; j ++)
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % p;
}

void dfs(int b, int d, int D, int x, ll sum)
{
    int cnt = 2 * b; //红色必须有黑节点承担  
    if(x < 0) return;   
    if(d == D - 1)
    {
        ans = ans + sum * c[cnt][x] % p;
        ans %= p;
        return;
    }
    for(int i = 0; i <= cnt; i ++) //枚举红色节点 
    {
        ll q = c[cnt][i];
        dfs(cnt + i, d + 1, D, x - (cnt + 2 * i), sum * q % p);
    }
}

int main()
{
    pre();
        scanf("%d", &n);
    for(int i = 1; i <= 20; i ++)
    {
        if(bin[i] > n) break;
        if(n >= bin[i] - 1 && n <= bin[2 * i] - 1)
           dfs(1, 0, i, n - 1, 1);
    }
    for(int i = 1; i <= 20; i ++)
        if(n == bin[i] - 1) ans ++;
    printf("%lld", ans % p);

    return 0;
}

心得

根据题目性质设计状态,往往可以得到一个不错的状态转移。


  转载请注明: iSecloud's Blog 1007. Red-black Tree

 上一篇
[HAOI2015]树上染色 [HAOI2015]树上染色
[HAOI2015]树上染色标签: 动态规划 树形结构 树形DP 题目描述有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 。 将所有点
2019-04-21
下一篇 
股票市场Stock Market 股票市场Stock Market
股票市场Stock Market标签: 动态规划 背包DP 题目描述尽管奶牛天生谨慎,它们仍然在住房抵押信贷市场中大受打击,现在它们准备在股市上碰碰运气。贝西有内部消息,她知道S只股票在今后D天内的价格。假设在一开始,她筹集了M元钱,那么
2019-03-26