二叉树★DP★二叉树的计数

题目

时间限制: 1 Sec 内存限制: 64 MB

题目描述

输入

第1行:二叉树的前序遍历顺序 第2行:后序遍历顺序

输出

第1行:1个整数,表示所有可能的二叉树的数量

样例输入

ABC
CBA

样例输出

4

分析

令先序遍历为 s1 ,后序遍历为 s2

定义状态

f(l1,r1,l2,r2) :满足先序遍历为 s1[l1,...,r1] ,后序遍历为 s2[l2,...r2] 的子树的棵数。

转移

对于 f(l1,r1,l2,r2) 这棵子树的种类数,一定是:左子树的种类数 × 右子树种类数。注意一点:当左右子树有一个为空时,另一个子树可以“移栽”在空的这个子树的位置上,所以种类数要乘2

所以,要找出 f(l1,r1,l2,r2) 的两个子树。

能确定的是: f(l1,r1,l2,r2) 的左子树的根一定是 s1[l1+1] ,原因自己想。
所以,在 s2[l2,...r2] 找到 s1[l1+1] 的位置 p ,那么左右子树在后序中的位置就出来了,分别为 s2[l2,...,p] s2[p+1,r2]

由于在先序中,一个子树一定是连续的一个串,所以在根右边的 0(pl2) 个全部是左子树,那剩下的就是右子树了。所以左右子树分别为 s1[l1+1,...,l1+(pl2+1)] s1[l1+(pl2+1)+1,...,r1]

所以: f(l1,l2,r1,r2)=f(l1+(pl2+1)+1,r1,p+1,r21)f(l1+1,l1+(pl2+1),l2,p)

边界

当只有两个结点时,显然return 2
只有一个结点,return 1
当子树为空时,return 2(处理之前说的“移栽”的情况)。

当找不到 p 时,说明这个子树也为空了,给 p 一个极大值(让 f 返回2)即可。

代码

#include<cstdio>
#include<cstring>

#define MAXN 26
char s1[MAXN+5],s2[MAXN+5];
int N;

int Find(char t,int l,int r)
{
    for(int i=l;i<=r;i++)
        if(s2[i]==t)
            return i;
    return MAXN+2;//找不到p
}

int dfs(int l1,int r1,int l2,int r2)
{
    if(r2<l2) return 2;
    if(r2-l2+1<=2) return r2-l2+1;//结点数<=2
    int p=Find(s1[l1+1],l2,r2);
    return dfs(l1+(p-l2+1)+1,r1,p+1,r2-1)*
           dfs(l1+1,l1+(p-l2+1),l2,p);
}

int main()
{
    scanf("%s%s",s1+1,s2+1);
    N=strlen(s1+1);
    printf("%d",dfs(1,N,1,N));
}

猜你喜欢

转载自blog.csdn.net/c20190102/article/details/78872438