POJ 1635

原博地址:http://www.cnblogs.com/rainydays/archive/2011/06/15/2081779.html

题意:给出两棵树的深度遍历序列,0表示远离根,1表示向根走。判断两树是否同构。

分析:利用树的最小表示,

定义S[t]表示以t为根的子树的括号序列

S[t]={‘(‘,S[c1],S[c2],…,S[ck],’)’ (c1,c2,…,ck为t的k个子节点,S[c1],S[c2],…,S[ck]要按照字典序排列)}

为了保证同构的树的括号序列表示具有唯一性,我们必须规定子树点的顺序。按照子树的括号序列的字典序就是一种不错的方法。

真正操作的过程中要用深度优先遍历全树,当遍历完一个子树时要对这个子树根节点所连接的所有子节点进行排序。整个过程不需要

建树,但是要记录每个子树对应的字符串的起始和结束位置。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<algorithm>
#include<vector>
#define mx 3005
#define y1 y12345
#define inf 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

struct Tree{int l,r;}tree[mx];
char st1[mx],st2[mx],temp[mx],st[mx];
//排序
bool cmp(Tree a,Tree b){
    int len=min(a.r-a.l,b.r-b.l);        //两棵子树的字符串长度
    for(int i=0;i<len;i++){              //按照字符串字典序排序
        if(st[a.l+i]!=st[b.l+i])
        return st[a.l+i]<st[b.l+i];
    }
    return a.r-a.l<b.r-b.l;
}
void make(int l,int r,Tree *tree){
    int zcount=0;
    int tcount=0;                     //[l,r]中子节点的个数
    int s=l;
    for(int i=l;i<r;i++){
        if(st[i]=='0')zcount++;
        else zcount--;
        if(zcount==0){                //当i为[l,r]中的一个子节点时
            make(s+1,i,&tree[tcount]);     //递归找到结点i的子节点
            tree[tcount].l=s;       //子结点i的字符串的起始位置
            tree[tcount].r=i+1;     //子节点i的字符串的结束位置
            tcount++;                 //子节点编号+1
            s=i+1;                    //下一个子节点的起始位置
        }
    }
    sort(tree,tree+tcount,cmp);   //将子节点们的字符串进行字典序排序
    s=l;
    for(int i=0;i<tcount;i++){
        for(int j=tree[i].l;j<tree[i].r;j++)
        temp[j-tree[i].l+s]=st[j];
        s+=tree[i].r-tree[i].l;
    }
    for(int i=l;i<r;i++)
    st[i]=temp[i];
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%s",st);
        make(0,strlen(st),tree);
        strcpy(st1,st);
        scanf("%s",st);
        make(0,strlen(st),tree);
        strcpy(st2,st);
        if(strcmp(st1,st2)==0)
        printf("same\n");
        else printf("different\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值