uva12219 Common Subexpression Elimination

本文介绍了一种针对特定语法的表达式树压缩为图的方法,利用共享子表达式的方式减少重复节点,实现更紧凑的表示。通过深度优先搜索进行树构建与去重,并采用哈希值辅助的结构对比确保效率。

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");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值