##原题
###输入
第1行:二叉树的前序遍历顺序
第2行:后序遍历顺序
###输出
第1行:1个整数,表示所有可能的二叉树的数量
###样例输入1
ABC
CBA
###样例输出1
4
###样例输入2
ABCEDFGH
ECDBHGFA
###样例输出2
4
##分析
这道题也许你一拿到会觉得很难,甚至动起了爆搜的念头,但是这道题主要是弄清思路,其他就很简单了。
由于样例一的数据太简单了,所以我们分析样例二的数据。
###左子树?右子树?怎么找?
在先序中,左子树的根是紧跟在整棵树的根之后访问的,因此左子树的根在S1[1],即字符B.
在后序中,左子树的根是整个左子树最后一个被访问的,因此利用find函数,可以返回后序串S2中左子树根的位置:
T = S2.find(S1[1])
T也表示了左子树结点的个数. 因此:
左子树的后序串为:S2.substr(0, T) = BCED
左子树的先序串为:S1.substr(1, T) = ECDB
右子树的先序串为:S1.substr(T+2, S1.size()-T-1) = FGH
右子树的后序串为:S2.substr(T+1, S1.size()-T-1) = HGF
###左子树的递归处理
先序:BCED
后序:ECDB
####左子树
先序:CE
后序:EC
####右子树
先序:D
后序:D
左子树有2种形态,右子树有1种形态。根据乘法原理,整棵树有2种形态。
###右子树的递归处理
先序: FGH
后序: HGF
####左子子树:
先序:GH
后序:HG
####右子子树:空
左子子树有2种形态。因右子子树为空,左子子树可出现在右子子树的位置。这样右了树就可以有2*2=4种形态。
###总结
若当前树只有1个结点,则形态数为1.
否则根据前述方法划分左子树和右子树。若右子树为空,则总的形态数=左子树的形态数2.
若右子树不为空,则总的形态数=左子树的形态数右子树的形态数。
思路得出来了,程序就好写了许多。
##源代码
#include<cstdio>
#include<cstring>
char a[101],b[101];
int count(int x,int y,int q,int w){
if(w-q<0) return 2;
if(w-q<2) return w-q+1;
int p=strchr(b,a[q+1])-b;
return count(x,p,q+1,q+1+p-x)*count(p+1,y-1,q+2+p-x,w);
}
int main()
{
scanf("%s%s",a,b);
int n=strlen(a);
printf("%d",count(0,n-1,0,n-1));
}
是不是很简单啊。所以我们总结出,以后做题的时候一定要想好了再写程序,否则就会想这样臃肿:
#include<iostream>
#include<cstdio>
using namespace std;
int cnt=1,len1,len2;
void zhao(string s1,string s2)
{
int l1=s1.length();
int l2=s2.length();
if(l1<=2||l2<=2)
{
if(s1[0]==s2[1]&&s1[1]==s2[0])
cnt*=2;
return;
}
else if(s1[1]==s2[l2-2])
{
cnt*=2;
zhao(s1.substr(1,l1-1),s2.substr(0,l2-1));
}
else if(s1[1]!=s2[l2-2])
{
int o,p;
for(int i=0;i<=len1;i++)
if(s2[l2-2]==s1[i])
o=i;
for(int i=0;i<=len2;i++)
if(s2[i]==s1[1])
p=i;
zhao(s1.substr(1,o-1),s2.substr(0,p+1));
zhao(s1.substr(o,l1-o),s2.substr(p+1,l1-o));
}
}
int main()
{
string n,m;
cin>>n;
len1=n.length();
cin>>m;
len2=m.length();
zhao(n,m);
cout<<cnt;
}