问题
分析
就是建树,然后使用map和数组将子树映射成编号
用一个数据结构存储树,只保存子树的编号和自己的hash,string,然后就可唯一确定自己的编号
注意: 不能让a对应0
tnode.hash=tnode.hash*27+(*ptr-‘a’+1);// 区分aaa和a
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int maxn=70005;
struct node{
string s;
int hash,left,right;
node(string s="",int hash=0,int left=-1,int right=-1): s(s),hash(hash),left(left),right(right){}
bool operator < (const node &rhs) const {
if(hash!=rhs.hash) return hash<rhs.hash;
if(left!=rhs.left) return left<rhs.left;
return right<rhs.right;
}
}id2tree[maxn];
map<node,int> tree2id;
char ch[8*maxn],*ptr;
int T,kase=1,cnt=0,done[maxn];
//解析一个a(b,c)类似的结构,将它变成一颗树,然后按照顺序给节点编号
int parse(){
int id=++cnt;
//初始化空间,分配一块空的存储空间
node &tnode=id2tree[id];
tnode.s="";
tnode.hash=0;
tnode.left=tnode.right=-1;
//提取a
while(isalpha(*ptr)){
tnode.hash=tnode.hash*27+(*ptr-'a'+1);// 区分aaa和a
tnode.s.push_back(*ptr);
++ptr;
}
//处理b和c
if(*ptr=='('){
++ptr; //跨过(
tnode.left=parse();
++ptr; //跨过逗号
tnode.right=parse();
++ptr; //跨过)
}
//查找以前是否存在相同的数
if(tree2id.count(tnode)>0){
--cnt; //如果存在,放弃这个节点,直接返回同样的子树的序号
return tree2id[tnode];
}
return tree2id[tnode]=id;
}
void print(int d){
if(done[d]==kase){
printf("%d",d);
return;
}
done[d]=kase;
printf("%s",id2tree[d].s.c_str());
if(id2tree[d].left==-1) return;
printf("(");
print(id2tree[d].left);
printf(",");
print(id2tree[d].right);
printf(")");
}
int main(void){
// freopen("../UVaCh11/sample11_1/sample11_1_in.txt","r",stdin);
// freopen("../UVaCh11/sample11_1/sample11_1_out.txt","w",stdout);
scanf("%d",&T);
while(kase<=T){
scanf("%s",ch);
cnt=0;
tree2id.clear();
ptr=ch;
int root=parse();
print(root);
printf("\n");
kase++;
}
return 0;
}