Description
Let the set Σ consist of all words composed of 1-4 lower case letters, such as the words “a”, “b”, “f”,
“aa”, “fun” and “kvqf”. Consider expressions according to the grammar with the two rules
E → f
E → f(E, E)
for every symbol f ∈ Σ. Any expression can easily be represented as a tree according to its syntax. For
example, the expression “a(b(f(a,a),b(f(a,a),f)),f(b(f(a,a),b(f(a,a),f)),f))” is represented
by the tree on the left in the following figure:
Last night you dreamt of a great invention which considerably reduces the size of the representation:
use a graph instead of a tree, to share common subexpressions. For example, the expression above can
be represented by the graph on the right in the figure. While the tree contains 21 nodes, the graph just
contains 7 nodes.
Since the tree on the left in the figure is also a graph, the representation using graphs is not
necessarily unique. Given an expression, find a graph representing the expression with as few nodes as
possible!
Input
The first line of the input contains the number c (1 ≤ c ≤ 200), the number of expressions. Each of
the following c lines contains an expression according to the given syntax, without any whitespace. Its
tree representation contains at most 50 000 nodes.
Output
For each expression, print a single line containing a graph representation with as few nodes as possible.
The graph representation is written down as a string by replacing the appropriate subexpressions
with numbers. Each number points to the root node of the subexpression which should be inserted at
that position. Nodes are numbered sequentially, starting with 1; this numbering includes just the nodes
of the graph (not those which have been replaced by numbers). Numbers must point to nodes written
down before (no forward pointers). For our example, we obtain ‘a(b(f(a,4),b(3,f)),f(2,6))’.
Sample Input
3
this(is(a,tiny),tree)
a(b(f(a,a),b(f(a,a),f)),f(b(f(a,a),b(f(a,a),f)),f))
z(zz(zzzz(zz,z),zzzz(zz,z)),zzzz(zz(zzzz(zz,z),zzzz(zz,z)),z))
Sample Output
this(is(a,tiny),tree)
a(b(f(a,4),b(3,f)),f(2,6))
z(zz(zzzz(zz,z),3),zzzz(2,5))
CODE
#include<stdio.h>
#include<iostream>
#include<map>
#include<string.h>
#include<string>
using namespace std;
string s;
int k,cnt;
map<int,int> done;
struct tree
{
string s;
int ls,rs;
bool operator < (const tree& rhs) const//要用map一定要重载运算符。
{
if(s!=rhs.s)
return s<rhs.s;
else if(ls!=rhs.ls)
return ls<rhs.ls;
else
return rs<rhs.rs;
}
};
map<tree,int> MAP;//保存ID
map<int,tree> NODE;//保存节点信息
int solve()//只扫描一遍,好棒。
{
string cur;
while(s[k]>='a'&&s[k]<='z')
cur.push_back(s[k++]);
int id=++cnt;//这里是先给你预留一个编号的意思。
tree& t = NODE[id];//引用,好灵活。
t.s=cur;
t.ls=0;
t.rs=0;
if(s[k]=='(')
{
//写得简单易懂,跳过非字母的字符。
k++;
t.ls=solve();k++;
t.rs=solve();k++;
}
if(MAP[t]) //如果MAP[t]!=0,那么cnt必为id+1,cnt--即可取消预留的编号。
{
cnt--;
return MAP[t];
}
else
return MAP[t]=id;
}
void print(int u)
{
if(done[u])
printf("%d",u);
else
{
done[u]=1;
cout<<NODE[u].s;
if(NODE[u].ls)
{
cout<<"(";
print(NODE[u].ls);
cout<<",";
print(NODE[u].rs);
cout<<")";
}
}
}
int main()
{
int q;
cin>>q;
while(q--)
{
MAP.clear();
done.clear();
NODE.clear();
cnt=k=0;
cin>>s;
print(solve());//solve返回根编号,print从根标号开始递归输出。
puts("");
}
return 0;
}
代码解释
map内部是利用红黑树排序
红黑树排序只是用’<’所以只需重载’<’
1:a
cur:a
id = cnt = 1;
NODE[1] -> t;//引用
初始化t(NODE[1])
如果这个字符是’(’
{
跳过’(’
对以cur中字符串为根节点的数进行递归
左递归
右递归
}
如果这个树再map中出现了,即这个是公共表达式
cnt–//cnt不用再加了,用那个公共表达式的值即可(例如标记4,两个a都是4)
else
MAP中给这个树标记她的值id
代码部分过程
第一遍:
k:0
cur:a;
k++ == 1;
id = cnt =1;
NODE[1] = t = {a,0,0}
MAP[NODE[1]] = 1;
s[1]:(
k++ == 2
NODE[1].ls->solve()
第二遍
k:2
cur:b;
k++ == 3
id = cnt =2;
NODE[2] = t = {b, 0, 0}
s[3]:(
k++ == 4
NODE[2].ls->solve()
第三遍
k:4
cur:f
k++ == 5
id = cnt = 3
NODE[3] = t = {f,0,0}
s[5]:(
k++ == 6
NODE[3].ls->solve()
第四遍
k:6
cur:a
k++ == 7
id = cnt = 4
NODE[4] = {a,0,0}
s[7]:,
return MAP[NODE[4]] == 4;
{NODE[3].ls = MAP[NODE[4]](4)}
k++ == 8
NODE[3].rs->solve()
k:8
cur:a
k++ == 9
id = cnt = 5
NODE[5] = {a,0,0}
s[9]:)
cnt-- == 4
return MAP[NODE[5]];
{NODE[3].rs = MAP[NODE[5]](4)}
k++ == 10
MAP[NODE[3]] == 0
return MAP[NODE[3]] = 3
{NODE[2].ls = MAP[NODE[3](3)}
k++ == 11
NODE[2].rs->solve()
k:11
cur:b
k++ == 12
id = cnt = 4
NODE[4]