UVa 12219

题意大体是给定一个字符串,根据字符串建树,然后可以把树化简成一个图,最后根据图输出一行字符串


思路

      映射


题目就是要求化简子树,使每一个子树都唯一存在,可以用一个三元组SubTree(root, l, r)代表整个子树,root是当前子树根的字符串,

l是当前子树的左子树,r是当前子树的右子树,每次用map查询可以实现O(logn)的查询,建树的时候直接从左到右扫描字符串,如果

当前字符是'(',则递归继续建树,否则则表示当前的子树已经构建完成,给每一个子树一个旧编号,用一个固定数组存下来,遍历的

时候用题目要求的新编号取代旧编号递归输出即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 10;
const int maxd = 50000 + 10;
int nc;
struct SubTree{
    string root;
    int l, r;
    SubTree(){root = ""; l = r = 0;}
    SubTree(string root, int l, int r) : root(root), l(l), r(r){}
    bool operator < (const SubTree & rhs) const {
        return root <rhs.root
        || (root == rhs.root && l < rhs.l)
        || (root == rhs.root && l == rhs.l && r < rhs.r);
    }
}subtree[maxd];
map<SubTree, int> ID;
int nID[maxn];
bool isexp(char ch){
    return ch == '(' || ch == ')' || ch == ',';
}
int pos;
int build_tree(char * s){
    SubTree st;
    while(isalpha(s[pos])){
        st.root.push_back(s[pos]);
        pos++;
    }
    if(s[pos] == '('){
        pos++;
        st.l = build_tree(s);
        st.r = build_tree(s);
    }
    pos++;
    if(!ID.count(st)){
        ID[st] = ++nc;
        subtree[nc] = st;
    }
    return ID[st];
}
set<int> ss;
void print(int root){
    SubTree & st = subtree[root];
    int id = ID[st];
    if(!ss.count(id)){
        printf("%s", st.root.c_str());
        nID[id] = ++nc;
        ss.insert(id);
        if(st.l == 0 && st.r == 0) return;
        putchar('('); print(st.l);
        putchar(','); print(st.r);
        putchar(')');
    }else {
        printf("%d", nID[id]);
        return;
    }
}

void solve(char * s){
    int len = strlen(s);
    pos = 0;
    int root = build_tree(s);
    nc = 0;
    print(root); putchar('\n');
}


char s[maxn];

void init(){
    nc = 0;
    ID.clear();
    ss.clear();
}

int main()
{
    int n; scanf("%d", &n);
    while(n --){
        init();
        scanf("%s", s);
        solve(s);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值