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 2 . 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 gure: 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 gure. While the tree contains 21
nodes, the graph just contains 7 nodes. Since the tree on the left in
the gure is also a graph, the representation using graphs is not
necessarily unique. Given an expression, nd a graph representing the
expression with as few nodes as possible! Input The rst 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)) ‘
通过dfs进行建树和去重,关键是判断两棵树是否完全相同。可以对子树进行编号,每个三元组{自身的字符串(的哈希值),左子树编号,右子树编号}对应唯一的编号,在map里进行查询。
注意时限卡的比较紧,建树要做到O(n)。
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<algorithm>
#include<map>
#include<iostream>
using namespace std;
#define LL unsigned long long
const int pp=131;
struct st
{
char s[5];
int u,v,l;
LL h;
bool operator < (const st ss) const
{
int i;
if (h!=ss.h) return h<ss.h;
if (u!=ss.u) return u<ss.u;
return v<ss.v;
}
}a[1000000];
map<st,int> mp;
char s[500000];
int len[1000000],num[1000000],ord[1000000],last[1000000],tot,l,r,cnt,clo,now,K;
bool b[1000000];
int build()
{
int i,j,k,cnt,q;
bool flag=0;
st tem;
tem.l=tem.h=0;
while (now<=l&&(s[now]!=','&&s[now]!='('&&s[now]!=')'))
{
tem.s[++tem.l]=s[now];
tem.h=tem.h*pp+s[now];
now++;
}
tem.s[tem.l+1]=0;
if (s[now]=='(')
{
now++;
tem.u=build();
now++;
tem.v=build();
now++;
}
else tem.u=tem.v=0;
if (!mp.count(tem))
{
a[++tot]=tem;
mp[tem]=tot;
}
return mp[tem];
}
void prt(int p)
{
if (last[p]<K)
{
last[p]=K;
ord[p]=++clo;
printf("%s",a[p].s+1);
if (!a[p].u) return;
printf("(");
prt(a[p].u);
printf(",");
prt(a[p].v);
printf(")");
}
else printf("%d",ord[p]);
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
K++;
scanf("%s",s+1);
l=strlen(s+1);
tot=0;
now=1;
clo=0;
cnt=0;
mp.clear();
prt(build());
printf("\n");
}
}