Common Subexpression Elimination UVA - 12219

问题

分析

就是建树,然后使用map和数组将子树映射成编号
用一个数据结构存储树,只保存子树的编号和自己的hash,string,然后就可唯一确定自己的编号
注意: 不能让a对应0
tnode.hash=tnode.hash*27+(*ptr-‘a’+1);// 区分aaa和a

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int maxn=70005;
struct node{
    string s;
    int hash,left,right;
    node(string s="",int hash=0,int left=-1,int right=-1): s(s),hash(hash),left(left),right(right){}
    bool operator < (const node &rhs) const {
        if(hash!=rhs.hash) return hash<rhs.hash;
        if(left!=rhs.left) return left<rhs.left;
        return right<rhs.right;
    }
}id2tree[maxn];
map<node,int> tree2id;
char ch[8*maxn],*ptr;
int T,kase=1,cnt=0,done[maxn];
//解析一个a(b,c)类似的结构,将它变成一颗树,然后按照顺序给节点编号
int parse(){
    int id=++cnt;
    //初始化空间,分配一块空的存储空间
    node &tnode=id2tree[id];
    tnode.s="";
    tnode.hash=0;
    tnode.left=tnode.right=-1;
    //提取a
    while(isalpha(*ptr)){
        tnode.hash=tnode.hash*27+(*ptr-'a'+1);// 区分aaa和a
        tnode.s.push_back(*ptr);
        ++ptr;
    }
    //处理b和c
    if(*ptr=='('){
        ++ptr;  //跨过(
        tnode.left=parse();
        ++ptr;  //跨过逗号
        tnode.right=parse();
        ++ptr;  //跨过)
    }
    //查找以前是否存在相同的数
    if(tree2id.count(tnode)>0){
        --cnt;  //如果存在,放弃这个节点,直接返回同样的子树的序号
        return tree2id[tnode];
    }
    return tree2id[tnode]=id;
}

void print(int d){
    if(done[d]==kase){
        printf("%d",d);
        return;
    }
    done[d]=kase;
    printf("%s",id2tree[d].s.c_str());
    if(id2tree[d].left==-1) return;
    printf("(");
    print(id2tree[d].left);
    printf(",");
    print(id2tree[d].right);
    printf(")");
}

int main(void){
//    freopen("../UVaCh11/sample11_1/sample11_1_in.txt","r",stdin);
//    freopen("../UVaCh11/sample11_1/sample11_1_out.txt","w",stdout);
    scanf("%d",&T);
    while(kase<=T){
        scanf("%s",ch);
        cnt=0;
        tree2id.clear();
        ptr=ch;
        int root=parse();
        print(root);
        printf("\n");
        kase++;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值