这题和普通的表达式树很像,但如果按照一般的做法(用L、R代表范围),会TLE,因为重复了太多无用的扫描
这题树中的结点对应的子树都是二叉树,不存在只有一个儿子的情况。输入的字符串中也只有两种情况,结点名字后面紧跟一个左括号的,和不跟括号的。
因此很容易判断一个结点是否为叶子结点:只要在原字符串中看他后面有没有紧跟着左括号就行了。如果有,立刻递归建树作为左子树。因为有左子树就一定有右子树,所以左子树建完后就可以从字符串中左子树结束的位置开始建右子树了。因此不需要从左到右扫描寻找逗号来分割左右子树。
至于树的判重,参考UVa #12096 The SetStack Computer (例题5-5)
另外字符串的对比是缓慢的。鉴于这道题最多只有四个小写字母,也就是最多26*4种情况,我们完全可以用整数来代替字符串。一种比较简单的做法是把字符串看成一个四位的27进制数,并抛弃0,因为0和0000相等。
Run Time: 1.075s
#define UVa "LT11-1.12219.cpp" //Common Subexpression Elimination
char fileIn[30] = UVa, fileOut[30] = UVa;
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
void decode(int a) {
vector<char> result;
while(a) { result.push_back(a%27+'a'-1); a/=27; } //%27+1
for(int i = result.size() - 1; i >= 0; i --) {
cout<<result[i];
}
}
struct Tree {
int rcode, lch, rch; //code of root. treeid of left and right sub-tree.
Tree(){}
Tree(int a, int b, int c):rcode(a), lch(b), rch(c) { }
bool operator < (const Tree& rhs) const {
if(rcode == rhs.rcode){
if(lch == rhs.lch) return rch < rhs.rch;
return lch < rhs.lch;
}
return rcode < rhs.rcode;
}
};
//Global Variables. Reset upon Each Case!
const int maxn = 50000+5;
int T, treecnt, vis[maxn], ans[maxn], cnt;
char str[5*(maxn+10000)], *p;
Tree trees[maxn];
map<Tree, int> tree_map;
/
int getTreeID(Tree& t) {
if(tree_map.count(t)) return tree_map[t];
else {
Tree& v = trees[treecnt];
v = t;
return tree_map[t] = treecnt++;
}
}
int parse() {
int lch = -1, rch = -1;
int name = 0;
while(isalpha(*p)) {
name = name*27 + (*p-'a'+1);
p ++;
}
if(*p == '(') {
p++;
lch = parse();
p ++;
rch = parse();
p ++;
}
Tree tmp = Tree(name, lch, rch);
return getTreeID(tmp);
}
void print_ans(int id) {
if(ans[id] != -1) cout<<ans[id];
else {
ans[id] = ++cnt;
decode(trees[id].rcode);
if(trees[id].lch != -1) {
cout<<"(";
print_ans(trees[id].lch);
cout<<",";
print_ans(trees[id].rch);
cout<<")";
}
}
}
int main() {
memset(vis, -1, sizeof(vis));
cin>>T;
while(T--) {
treecnt = cnt = 0;;
tree_map.clear();
scanf("%s", str);
p = str;
memset(ans, -1, sizeof(ans));
print_ans(parse());
cout<<endl;
}
return 0;
}