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 rulesE → fE → f(E, E)for every symbol f ∈ Σ. Any expression can easily be represented as a tree according to its syntax. Forexample, the expression “a(b(f(a,a),b(f(a,a),f)),f(b(f(a,a),b(f(a,a),f)),f))” is representedby 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 canbe represented by the graph on the right in the figure. While the tree contains 21 nodes, the graph justcontains 7 nodes.Since the tree on the left in the figure is also a graph, the representation using graphs is notnecessarily unique. Given an expression, find a graph representing the expression with as few nodes aspossible!InputThe first line of the input contains the number c (1 ≤ c ≤ 200), the number of expressions. Each ofthe following c lines contains an expression according to the given syntax, without any whitespace. Itstree representation contains at most 50 000 nodes.OutputFor 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 subexpressionswith numbers. Each number points to the root node of the subexpression which should be inserted atthat position. Nodes are numbered sequentially, starting with 1; this numbering includes just the nodesof the graph (not those which have been replaced by numbers). Numbers must point to nodes writtendown before (no forward pointers). For our example, we obtain ‘a(b(f(a,4),b(3,f)),f(2,6))’.Sample Input3this(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 Outputthis(is(a,tiny),tree)a(b(f(a,4),b(3,f)),f(2,6))z(zz(zzzz(zz,z),3),zzzz(2,5))
这题我半年前就看了,不会写。。折磨了我半年之久。。今天终于中奖了。
【分析】
字符串转二叉树是个难点,首先要正确的将字符串内容分离出来。
字符串转化二叉树(静态空间):
英文单词作为结点名字,左右孩子默认为0(空),若该单词后有‘(’,则存在子树,若还存在‘,’则有两颗子树。
以此递归建树,并且用map辅助,相同的子树只建立一次。
只要建树成功,输出就好说了,递归输出并且编号就好了。
预处理:
R[i]:字符串第i个位置的‘(’对应的‘)’位置
D[i]:字符串第i个位置的‘)’对应的‘,’位置
【代码】
#include<bits/stdc++.h>
using namespace std;
struct node{
string name;
int l,r;
node(string a="",int L=0,int R=0){
name=a;l=L;r=R;
}
bool operator<(const node &b)const //map内部排序
{
if(name==)
if(l==b.l)return r<b.r;
else return l<b.l;
return name<;
}
}e[50505];
int cnt,dex; //结点计数
char s[1010101];
int D[1010101],R[1010101]; //, )
int vis[50500];
map<node,int>M;
int build(int l,int r) //先建树,公共树消除
{
int i=l;
while(isalpha(s[i]))i++;
char t=s[i];
s[i]=0;
string str(&s[l]);
s[i]=t; // ) ( ,\0
node p(str,0,0);
if(t=='(') //有子树
{
if(D[R[i]])//有逗号,双子树
{
p.l=build(i+1,D[R[i]]-1);
p.r=build(D[R[i]]+1,r-1);
}
else p.l=build(i+1,r-1);
}
if(M.count(p)) return M[p];
e[M[p]=++cnt]=p;
return cnt;
}
void dfs(int u)
{
if(vis[u]){
printf("%d",vis[u]);
return;
}
vis[u]=++dex;
printf("%s",&e[u].name[0]);
if(e[u].l) //存在子树
{
printf("(");
dfs(e[u].l);
if(e[u].r)printf(","),dfs(e[u].r); //双子树
printf(")");
}
}
int main()
{
int T;cin>>T;
while(T--)
{
memset(D,0,sizeof(D));
memset(R,0,sizeof(R));
scanf("%s",s);
int st[101010],t=0;
for(int i=strlen(s)-1;i>=0;i--)
{
if(s[i]==')')st[t++]=i;
if(s[i]=='(')R[i]=st[--t];
if(s[i]==',')D[st[t-1]]=i;
}
M.clear(); cnt=0;
build(0,strlen(s)-1); //建树
memset(vis,0,sizeof(vis));
dex=0; //计数
dfs(cnt);
printf("\n");
}
}