UVALive 4847 Binary Search Tree【树型dp】

20 篇文章 0 订阅

题目大意:给定一个1-n的排列,依次将这些数插入到二叉排序树中,问总共有多少个排列使得构成的二叉树和给定的排列构成的二叉树相同

本题的思路就是:先构成要求的二叉排序树,然后再在树上进行dp

状态转移为:dp[rt] = dp[lson]*dp[rson]*c(lson,sum);

lson 表示左子树的点的个数,sum表示左右子树点的个数之和。

c(a,b) 表示b中过选择a个的组合数。状态转移应该是比较好理解的吧 

代码写的比较挫,毕竟不常写二叉树

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define mod 9999991
struct note
{
    int val,l,r,size;
    long long dp;
}dat[100];
int kk;
void init()
{
    for(int i = 0;i < 100;i++)
    {
        dat[i].l = dat[i].r = -1;
        dat[i].val = 0;
        dat[i].dp = 1;
        dat[i].size = 1;
    }
}
void insert(int rt,int val)
{
    if(val < dat[rt].val)
    {
        if(dat[rt].l == -1)
        {
            dat[rt].l = kk;
            dat[kk].val = val;
            kk++;
            return;
        }else insert(dat[rt].l,val);
    }else
    {
        if(dat[rt].r == -1)
        {
            dat[rt].r = kk;
            dat[kk].val = val;
            kk++;
            return;
        }else insert(dat[rt].r,val);
    }
}
long long c[100][100];
void C()
{
    int i,j;
    c[0][0]=1;
    for(i=1;i<40;i++)    //自定义
        for(j=0;j<=i;j++)
            c[i][j]=(j==0)?c[i-1][j]:c[i-1][j]+c[i-1][j-1];    //公式
}
void dfs(int rt)
{
    if(dat[rt].l == -1 && dat[rt].r == -1)
    {
        return;
    }
    if(dat[rt].l != -1) dfs(dat[rt].l);
    if(dat[rt].r != -1) dfs(dat[rt].r);
    if(dat[rt].l != -1 && dat[rt].r != -1)
    {
        dat[rt].size = dat[dat[rt].l].size + dat[dat[rt].r].size + 1;
        int cc = c[ dat[rt].size-1 ][ dat[dat[rt].l].size ];
        dat[rt].dp = cc*dat[dat[rt].l].dp * dat[dat[rt].r].dp%mod;
    }else if(dat[rt].l == -1)
    {
        dat[rt].size = dat[ dat[rt].r ].size+1;
        dat[rt].dp = dat[dat[rt].r].dp;
    }else
    {
        dat[rt].size = dat[ dat[rt].l ].size+1;
        dat[rt].dp = dat[dat[rt].l].dp;
    }
}
int main()
{
    C();
    //cout << c[20][10];
    int t;
    cin >> t;
    while(t--)
    {
        init();
        int n;
        cin >> n;
        int tt;
        kk = 2;
        for(int i = 0;i < n;i++)
        {
            cin >> tt;
            if(i == 0) dat[1].val = tt;
            else insert(1,tt);
        }

        dfs(1);
        cout << dat[1].dp << "\n";
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值