UVa 12219 公共表达式消除

https://vjudge.net/problem/UVA-12219

题意:

用表达式树来表示一个表达式。

 

思路:

用map来记录出现过的子树。如(b,3,6)表示这棵子树的根为b,左子树为编号为3的子树,右子树为编号为6的子树。

 1 #include<iostream> 
 2 #include<string>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<map>
 6 using namespace std;
 7 
 8 const int maxn = 60000;
 9 char s[maxn * 5], *p;
10 int cnt, kase;
11 int vis[maxn];
12 
13 struct node
14 {
15     string s;   //因为运算数是1~4个小写字母,所以这里要用string
16     int left, right;
17     bool operator < (const node& rhs)  const     //有map,所以一定要重载
18     {
19         if (s != rhs.s)       return s < rhs.s;
20         if (left != rhs.left)    return left < rhs.left;
21         return right < rhs.right;
22     }
23 }tree[maxn];
24 
25 map<node, int>dict;
26 
27 int solve()
28 {
29     int id = ++cnt;  //从1开始编号
30     node& t = tree[id];  //引用,比较方便
31     t.s = "";
32     t.left = t.right = -1;
33     while (*p >= 'a' && *p <= 'z')   //先把根输入进去
34     {
35         t.s.push_back(*p);
36         p++;
37     }
38 
39     //递归处理左右子树
40     if (*p == '(')
41     {
42         p++;  //跳过'('
43         t.left = solve(),  p++;     //跳过','
44         t.right = solve(), p++;     //跳过')'
45     }
46 
47     if (dict.count(t))   //如果已经出现过
48     {
49         cnt--;
50         return dict[t];   //直接返回子树编号
51     }
52     return dict[t] = id;  //没出现过,编号并返回
53 }
54 
55 
56 void print(int u)
57 {
58     if (vis[u]==kase)     cout << u ;   //如果子树已经输出过,直接输出编号
59     else
60     {
61         vis[u] = kase;
62         cout << tree[u].s;
63         //递归输出左右子树
64         if (tree[u].left != -1)
65         {
66             cout << "(";
67             print(tree[u].left);
68             cout << ",";
69             print(tree[u].right);
70             cout << ")";
71         }
72     }
73 }
74 
75 int main()
76 {
77     //freopen("D:\\txt.txt", "r", stdin);
78     int T;
79     cin >> T;
80     for (kase = 1; kase <= T;kase++)
81     {
82         dict.clear();
83         cnt = 0;
84         cin >> s;
85         p = s;
86         print(solve());  //返回根编号,递归输出
87         cout << endl;
88     }
89     return 0;
90 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/6385608.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值