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]
本文介绍了一种使用图来替代树的方法,以减少特定类型表达式树的节点数量,通过共享公共子表达式来达到压缩的目的,并提供了一个示例性的算法实现。

1941

被折叠的 条评论
为什么被折叠?



