原博地址:http://www.cnblogs.com/rainydays/archive/2011/06/15/2081779.html
题意:给出两棵树的深度遍历序列,0表示远离根,1表示向根走。判断两树是否同构。
分析:利用树的最小表示,
定义S[t]表示以t为根的子树的括号序列
S[t]={‘(‘,S[c1],S[c2],…,S[ck],’)’ (c1,c2,…,ck为t的k个子节点,S[c1],S[c2],…,S[ck]要按照字典序排列)}
为了保证同构的树的括号序列表示具有唯一性,我们必须规定子树点的顺序。按照子树的括号序列的字典序就是一种不错的方法。
真正操作的过程中要用深度优先遍历全树,当遍历完一个子树时要对这个子树根节点所连接的所有子节点进行排序。整个过程不需要
建树,但是要记录每个子树对应的字符串的起始和结束位置。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<algorithm>
#include<vector>
#define mx 3005
#define y1 y12345
#define inf 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
struct Tree{int l,r;}tree[mx];
char st1[mx],st2[mx],temp[mx],st[mx];
//排序
bool cmp(Tree a,Tree b){
int len=min(a.r-a.l,b.r-b.l); //两棵子树的字符串长度
for(int i=0;i<len;i++){ //按照字符串字典序排序
if(st[a.l+i]!=st[b.l+i])
return st[a.l+i]<st[b.l+i];
}
return a.r-a.l<b.r-b.l;
}
void make(int l,int r,Tree *tree){
int zcount=0;
int tcount=0; //[l,r]中子节点的个数
int s=l;
for(int i=l;i<r;i++){
if(st[i]=='0')zcount++;
else zcount--;
if(zcount==0){ //当i为[l,r]中的一个子节点时
make(s+1,i,&tree[tcount]); //递归找到结点i的子节点
tree[tcount].l=s; //子结点i的字符串的起始位置
tree[tcount].r=i+1; //子节点i的字符串的结束位置
tcount++; //子节点编号+1
s=i+1; //下一个子节点的起始位置
}
}
sort(tree,tree+tcount,cmp); //将子节点们的字符串进行字典序排序
s=l;
for(int i=0;i<tcount;i++){
for(int j=tree[i].l;j<tree[i].r;j++)
temp[j-tree[i].l+s]=st[j];
s+=tree[i].r-tree[i].l;
}
for(int i=l;i<r;i++)
st[i]=temp[i];
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",st);
make(0,strlen(st),tree);
strcpy(st1,st);
scanf("%s",st);
make(0,strlen(st),tree);
strcpy(st2,st);
if(strcmp(st1,st2)==0)
printf("same\n");
else printf("different\n");
}
return 0;
}