原题传送门;[NOIP2001 普及组] 求先序排列 - 洛谷
根在中序遍历的位置,左半边都是它的左子树,右半边都是它的右子树。
也就是说现在可以写出这个东西了
蒟蒻代码1号
#include <bits/stdc++.h>
using namespace std;
void travel(string mid,string back){
char root=back[back.length()-1];
int k=mid.find(root);
//左子树
travel(mid.substr(0,k));
//右子树
travel(mid.substr(k+1));
}
int main(){
string mid,back;
cin>>mid>>back;
travel(mid,back);
return 0;
}
因为输出的是back的最后一个,所以递归子树的back序列的最后一个要是子树的根,并且这个区间里面只能是子树的根集。
因为是递归产生的所以递归回去是正确的,不做证明。
画图即可找出对应区间。
蒟蒻代码2号(MLE)
#include <bits/stdc++.h>
using namespace std;
void travel(string mid,string back){
char root=back[back.length()-1];
cout<<root;
int k=mid.find(root);
//左子树
travel(mid.substr(0,k),back.substr(0,k));
//右子树
travel(mid.substr(k+1),back.substr(k,mid.size()-1-k));
}
int main(){
string mid,back;
cin>>mid>>back;
travel(mid,back);
return 0;
}
怎么会是呢,找子树的时候前提是还有子树可以找,即mid.length()>0
AC代码
#include <bits/stdc++.h>
using namespace std;
void travel(string mid,string back){
if(mid.length()>0){
char root=back[back.length()-1];
cout<<root;
int k=mid.find(root);
travel(mid.substr(0,k),back.substr(0,k));
travel(mid.substr(k+1),back.substr(k,mid.size()-1-k));
}
}
int main(){
string mid,back;
cin>>mid>>back;
travel(mid,back);
return 0;
}
根+子树关系才能确定一颗树,这题是中序+后序求前序,还有前序+中序求后序
对于这两种递归写法来说其实都是,利用两序递归建树。
递归建树的时候也就是相当于遍历了一遍,可以直接输出另一个序列。
[USACO3.4] 美国血统 American Heritage - 洛谷
那么同样的这道题画个图也出来了。
AC代码
#include <bits/stdc++.h>
using namespace std;
void travel(string mid,string pre){
if(mid.length()>0){
char root=pre[0];
int k=mid.find(root);
travel(mid.substr(0,k),pre.substr(1,k));
travel(mid.substr(k+1),pre.substr(k+1,mid.length()-1-k));
cout<<root;
}
}
int main(){
string mid,pre;
cin>>mid>>pre;
travel(mid,pre);
return 0;
}
虽说图画的是s-1,但是实际中m-1才代表子树的实际长度,所以里面要写mid.length()-1来取最后一个点。
那么通过前序序列和后序序列能求出有多少个不同的中序序列呢...
看题解的,如果一个节点只有一个子节点,那么不管这个子节点是在右边还是左边,是不会影响前序和后序的,但是中序会被改变。
手动模拟一下前序和后序,不难发现如果前序的后继节点是后序的前驱节点,那么这是一个孤儿节点
AC代码
#include <bits/stdc++.h>
using namespace std;
int ans=1;
string pre,back;
int main(){
cin>>pre>>back;
for(int i=0;i<pre.length();i++){
for(int j=1;j<back.length();j++){
if(pre[i]==back[j]&&pre[i+1]==back[j-1])ans<<=1;
}
}
cout<<ans;
return 0;
}