Uva12219

自己写了个代码,本来还沾沾自喜,因为刘汝佳老师是把树的结构建立起来以后再遍历了一遍,我是一边建树一边打印。结果发现TLE了,网友指点才发现时间卡得有点紧,所以遍历一定要做到O(n)才可以…但是这个代码沿袭了刘老师表达式树的idea所以并没有能O(n)…

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<limits.h>
#include<cmath>
#include<string>
#include<map>
typedef long long ll;
using namespace std;

const int nodemax=50000;
int nc;     //node count    //不重复的节点数
int c;      //<=200
int cur ;   //当前的节点数(包含重复
map<string,int> nodes;
string  str;

void build(int l,int r);

int main()
{
    //freopen("12219in.txt","r",stdin);
    cin>>c;
    while(c--)
    {
        cin>>str;
        nc=0;   
        nodes.clear();
        build(0,str.size());                
        cout<<endl;
    }
    return 0;
}

void  build(int l,int r)    //序号是int
{
    string now=str.substr(l,r-l);

    if (nodes[now])
    { 
        cout << nodes[now];
        return;
    }
    nodes[now]=++nc;        //nc从1开始(不含重复的)
    int lb=-1,com=-1;
        //先找第一个left bracket lb左括号 =ll-1
    int pos=l;
    while(str[pos]!='(' && pos<r) pos++;

    string output=str.substr(l,pos-l);
    cout<<output;

    if(pos==r)      //没找到(  即f的形式
        return ;

    int ll=pos+1;
    int bracket=0;  //用于判断,是否再括号外面
    for(pos++;pos<r;pos++)  //先越过当前的(
    {
        if(str[pos]=='(')
                bracket++;
        if(str[pos]==')')
                bracket--;
        if(str[pos]==',' && !bracket)
        {
            com=pos;break;
        }   
    }
    cout << "(";
    build(ll,com);
    cout << ",";
    build(com+1,r-1);
    cout << ")";
}

刘老师代码亦附上(膝行仰视):

// UVa12219 Common Subexpression Elimination
// Rujia Liu

#include<cstdio>
#include<string>
#include<map>
using namespace std;

const int maxn = 60000;
int T, kase, cnt;
char expr[maxn*5], *p;
int done[maxn]; // 该结点是否已输出

struct Node {
  string s;
  int hash, left, 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;
  }
} node[maxn];

map<Node,int> dict;

int parse() {
  int id = cnt++;     //明明id和cnt是一致的 为何要两个东西  因为后者是全局的!可能递归的过程中被改变了!
  Node& u = node[id]; //记录节点序号
  u.left = u.right = -1;
  u.s = "";
  u.hash = 0;
  while(isalpha(*p)) {        // 【记录下】  char &p=char a[];  所以p是a[0]的地址 
    u.hash = u.hash * 27 + *p - 'a' + 1;    //27进制的编码  0不用哦 因为0(a)和0000(aaaa)是一样的
    u.s.push_back(*p);
    p++;
  }
  if (*p == '(') { // (L,R)
    p++; u.left = parse(); p++; u.right = parse(); p++;   //最后一个p++ 越过) 因为这个p是全局的,后面可能要用
  }
  if (dict.count(u) != 0) { //已经出现过
    id--; cnt--;              //我肯定得等子树结束了才知道我跟人家重复了没  如果子树跟人家不重复 我肯定跟人家不会重复 如果子树跟人家重复了 子树并不会使cnt自增
    return dict[u];
  }
  return dict[u] = id;    //这个节点是未重复节点的第id个
}

void print(int v) {
  if(done[v] == kase)
    printf("%d", v + 1);
  else {      
    done[v] = kase; // 常见小技巧,可以避免memset(done, 0, sizeof(done))
    printf("%s", node[v].s.c_str());
    if(node[v].left != -1) {
      putchar('(');
      print(node[v].left);
      putchar(',');
      print(node[v].right);
      putchar(')');
    }
  }  
}

int main() {
  scanf("%d", &T);
  for(kase = 1; kase <= T; kase++) {
    dict.clear();
    cnt = 0;
    scanf("%s", expr);
    p = expr;
    print(parse());
    putchar('\n');    
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值