纪中21日c组T1 1575. 二叉树
1575. 二叉树
(File IO): input:tree.in output:tree.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制
题目描述
在众多的数据结构中,二叉树是一种特殊而重要的结构,有着广泛的应用。二叉树或者是一个节点,或者有且仅有一个节点位二叉树的根,其余节点被分成两个互不相交的子集,一个作为左子集,另一个作为右子集。每个子集又是一个二叉树。
遍历一棵二叉树就是按某条搜索路径巡访其中每个节点,使得每个节点均被访问一次,而且仅被访问一次。最常用的有三种遍历方式:
(1)前序遍历:若二叉树为空,则空操作;否则先访问根节点,接着前序遍历左子树,最后前序遍历右子树。
(2)中序遍历:若二叉树为空,则空操作;否则先中序遍历左子树,接着访问根节点,最后再中序遍历右子树。
(3)后序遍历:若二叉树为空,则空操作;否则先后序遍历左子树,接着后序遍历右子树,最后再访问根节点。
例如图1所示的二叉树前序遍历的顺序是ABCD,中序遍历的顺序是CBAD,后序遍历的顺序是CBDA。
对一棵二叉树,如果给出前序遍历和中序遍历的节点访问顺序,那么后序遍历的顺序是唯一确定的,也很方便地求出来。但如果现在只知道前序遍历和后序遍历的顺序,中序遍历的顺序是不确定的,例如:前序遍历的顺序是ABCD,而后序遍历的顺序是CBDA,那么就有两棵二叉树满足这样的顺序,见图1和图2。
现在的问题是给定前序遍历和后序遍历的顺序,要求出总共有多少棵不同形态的二叉树满足这样的遍历顺序。
输入
整个输入有两行,第一行给出前序遍历的访问顺序,第二行给出后序遍历的访问顺序。
二叉树的节点用一个大写字母表示,不会有两个节点标上相同字母。输入数据不包含空格,且保证至少有一棵二叉树符合要求。
输出
输出一个整数,为符合要求的不同形态的二叉树的数目。
样例输入
ABCD CBDA
样例输入
2
数据范围限制
题目中又没有……
我来补充吧:长度不会超过26.因为
二叉树的节点用一个大写字母表示,不会有两个节点标上相同字母
Solution
Algorithm1
暴力枚举2n呵呵
Code1
这么简单……我也不想打了
预计分数:100分左右
Algorithm2
找规律
只看前序和后序遍历
这两种遍历方式是反着的
也就是说,对于每一颗树,
在左序中是根节点->左节点->右节点;
在右序中是右节点->左节点->根节点。
所以
将左序从左开始,右序从右开始
相同的就直接去掉(说明是根节点)
不相同的话就从中剖开,分治再这样弄
Code2
bxd……不想打
呵呵
Algorithm3
因为相邻的点(父子关系)必定在一起
无论是左序还是右序(只是反过来了)
所以建立一个邻接矩阵
把左序中相邻的点连上
再一样的扫描右序,
看看相邻点的反向边是否存在
若存在,答案*2
这个方法我喜欢……
Code3
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<map> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #define IL inline 11 using namespace std; 12 IL int read() 13 { 14 int res=0; 15 char ch=getchar(); 16 while(ch<'0'||ch>'9') 17 ch=getchar(); 18 while(ch>='0'&&ch<='9') 19 res=(res<<1)+(res<<3)+(ch^48),ch=getchar(); 20 return res; 21 } 22 23 string a,b; 24 int ans=1; 25 bool memory[26][26]; 26 int main() 27 { 28 // freopen("tree.in","r",stdin); 29 // freopen("tree.out","w",stdout); 30 cin>>a>>b; 31 for(int i=0;i<a.size()-1;i++) 32 memory[a[i]-'A'][a[i+1]-'A']=1; 33 for(int i=0;i<b.size()-1;i++) 34 if(memory[b[i+1]-'A'][b[i]-'A']) ans*=2; 35 cout<<ans; 36 return 0; 37 }
End