现在的位置: 首页 > 综合 > 正文

UVA – 12219(唯一性标记法的应用)

2019年04月02日 ⁄ 综合 ⁄ 共 2637字 ⁄ 字号 评论关闭

用唯一性标记法,在递归建树时,给每个数分配唯一识别编号记为id  ,用map来记录(name,lson_id, rson_id)是否被标记过。

方法,很简单,但是有一点就是建树的时候遍历字符串,一定要做到o(n) ,否则超时。

下面为自己的,版本,简言之,先建树,唯一标记每棵子树,(因为序号分配是从下往上不同于题目要求,有重新转化为题目要求的编号)

#include <set>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;

const int maxn = 1005555;
struct node{
  string c;
  int l,r;
  node(string c="0",int l=0,int r=0):
      c(c),l(l),r(r){}
  bool operator <(const node& rhs)const{
    if(c!=rhs.c){
         return c < rhs.c;
    }
    else{
        return l<rhs.l||(l==rhs.l&&r<rhs.r);
    }
  }
};
map<node,int> vis;
vector<node> idcache;
int ID(node c){
  if(vis.count(c)) return vis[c];
  idcache.push_back(c);
  return vis[c]=idcache.size();
}
typedef struct tree* pointer;
struct tree{
  int id;
  string s;
  pointer Left,Right;
  tree(string s="0",pointer x=NULL,pointer y=NULL):
      s(s),Left(x),Right(y){}
};
pointer root;
char str[maxn],src[maxn],*p;
int build(pointer& u){
  u = new tree();
  int i,cnt=0;
  u->s.clear();
  while(islower(*p)){
    u->s.push_back(*p);
    p++;
  }
  if(*p!='('){
    return u->id=ID(node(u->s,0,0));
  }
  p++;
  int num1 = build(u->Left); p++;
  int num2 = build(u->Right); p++;
  return u->id=ID(node(u->s,num1,num2) );
}
void dfs(pointer u){
  if(u->Left==NULL){
     if(vis.count(node(u->s,0,0)))
         printf("%d",vis[node(u->s,0,0)]);
     else {
        ID(node(u->s,0,0));
        cout<<u->s;
     }
     return ;
  }
  if(vis.count(node(u->s,u->Left->id,u->Right->id)))
    printf("%d",vis[node(u->s,u->Left->id,u->Right->id)]);
  else{
    cout<<u->s;
    ID(node(u->s,u->Left->id,u->Right->id));
    printf("(");
    dfs(u->Left);
    printf(",");
    dfs(u->Right);
    printf(")");
  }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str);
        vis.clear();
        idcache.clear();
        p= str;
        build(root);
        vis.clear();
        idcache.clear();
        dfs(root);
        printf("\n");
    }
    return 0;
}

但是,可以用数组式建树预分配编号。若已经被访问取消预分配。

#include <set>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;

const int maxn = 100000;
char str[maxn*5],src[maxn],*p;
struct node{
  string s;
  int left,right,ha;
  bool operator < (const node& rhs)const{
     if(ha!=rhs.ha) return ha<rhs.ha;
     else if(left!=rhs.left) return left<rhs.left;
     else return right<rhs.right;
  }
}a[maxn];
int cn=0,fu=1;
map<node,int> vis;
int build(){
  int id = cn++;
  node& u=a[id];
  u.s.clear();
  u.ha = 0;
  u.left=u.right = -1;
  while(islower(*p)){
     char c = *p;
     u.s.push_back(c);
     u.ha=u.ha*27+(c)-'a'+1;
     p++;
  }
  if(*p=='('){
    p++;
    u.left=build(); p++;
    u.right=build(); p++;
  }
  if(vis.count(u)){
      cn--;
      return vis[u];
  }
  return vis[u] = id;
}
int T,V[maxn*6];
void dfs(int id){
  if(V[id] == T) printf("%d",id+1);
  else {
     V[id] = T;
     printf("%s",a[id].s.c_str());
     if(a[id].left!=-1){
     printf("(");
     dfs(a[id].left);
     printf(",");
     dfs(a[id].right);
     printf(")");
     }
  }
}
int main()
{
    int ca;
    scanf("%d",&ca);
    for(T=1;T<=ca;T++){
        scanf("%s",str);
        cn=0;
        vis.clear();
        p = str;
        build();
        dfs(0);
        printf("\n");
    }
    return 0;
}

抱歉!评论已关闭.