• bzoj 4337 树的同构


    4337: BJOI2015 树的同构

    Description

    树是一种很常见的数据结构。
    我们把N个点,N-1条边的连通无向图称为树。
    若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。
    对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相
    同,那么这两个树是同构的。也就是说,它们具有相同的形态。
    现在,给你M个有根树,请你把它们按同构关系分成若干个等价类。

    Input

    第一行,一个整数M。
    接下来M行,每行包含若干个整数,表示一个树。第一个整数N表示点数。接下来N
    个整数,依次表示编号为1到N的每个点的父亲结点的编号。根节点父亲结点编号为0。

    Output

    输出M行,每行一个整数,表示与每个树同构的树的最小编号。
     

    Sample Input

    4
    4 0 1 1 2
    4 2 0 2 3
    4 0 1 1 1
    4 0 1 2 3

    Sample Output

    1
    1
    3
    1

    HINT

    【样例解释】 

    编号为1, 2, 4 的树是同构的。编号为3 的树只与它自身同构。 

    100% 的数据中,1 ≤ N, M ≤ 50。 
     
     
     
    题意:
    给出M棵树,编号1~M,对于每棵树,询问与其同构的树的最小编号。
     
     
    题解:
    关键就在于如何判断两棵树是否同构。
    对于N个节点的无根树来说,枚举每个节点作为根,求最小表示法的序列。
     
    最小表示法:
    将子节点的最小表示序列排序(字符串字典序),把这些序列连接到一起,外面套一层小括号。
    递归回根节点生成的序列就是该树最小表示法。
     
    所以每棵树的最小表示法有N种。
    想要知道两棵树a,b是否同构,只需用a的一种最小表示法和b的所有最小表示法来比较,如果有相同,两棵树就是同构的。
     
    /*
    ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◆◆◆◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◇◆◆◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◇◆◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    ◇◇◇◇◇◇◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◆◆◆◇◆◆◆◇◇◇◇
    ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<ctime>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<vector>
    using namespace std;
    int read(){
        int xx=0,ff=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
        return xx*ff;
    }
    const int maxn=55;
    int T,N[maxn],lin[maxn],len;
    struct edge{
        int y,next;
    }e[maxn<<1];
    inline void insert(int xx,int yy){
        e[++len].next=lin[xx];
        lin[xx]=len;
        e[len].y=yy;
    }
    string H[maxn][maxn];
    string temp[maxn];
    int son[maxn][maxn],cnt[maxn];
    bool mycmp(const int &xx,const int &yy)
    {return temp[xx]<temp[yy];}
    void dfs(int x,int fa){
        cnt[x]=0;
        for(int i=lin[x];i;i=e[i].next)
            if(e[i].y!=fa){
                dfs(e[i].y,x);
                son[x][++cnt[x]]=e[i].y;
            }
        sort(&son[x][1],&son[x][cnt[x]+1],mycmp);
        temp[x]="(";
        for(int i=1;i<=cnt[x];i++)
            temp[x]+=temp[son[x][i]];
        temp[x]+=")";
    }
    bool check(int x,int y){
        if(N[x]!=N[y])
            return 0;
        for(int i=1;i<=N[x];i++)
            if(H[x][i]==H[y][1])
                return 1;
        return 0;
    }
    int main(){
        //freopen("in.txt","r",stdin);
        T=read();
        for(int i=1;i<=T;i++){
            N[i]=read();
            memset(lin,0,sizeof(lin));len=0;
            for(int j=1;j<=N[i];j++){
                int t=read();
                if(t)
                    insert(j,t),insert(t,j);
            }
            for(int j=1;j<=N[i];j++){
                dfs(j,0);
                H[i][j]=temp[j];
            }
        }
        for(int i=1;i<=T;i++)
            for(int j=1;j<=i;j++)
                if(check(i,j)){
                    printf("%d
    ",j);
                    break;
                }
        /*for(int i=1;i<=T;i++){
            for(int j=1;j<=N[i];j++)
                cout<<H[i][j]<<endl;
            cout<<endl;
        }*/
        return 0;
    }
    View Code
     
     
     
     
     
     
     
     
  • 相关阅读:
    转载.net泛型理解说明
    转载Repository 和Unit of work的使用说明
    libtool的工作原理
    带有通配符的字符串匹配算法-C/C++
    linux core文件机制
    grep多条件和sed合并两行
    BZOJ 3232 圈地游戏 (分数规划 + SPFA找负/正环)
    CSP2019 D1T3 树上的数 (贪心+并查集)
    CSP-S 2019 第二轮 退役记
    object-c中的int NSInteger NSUInteger NSNumber辨析
  • 原文地址:https://www.cnblogs.com/lzhAFO/p/8886512.html
Copyright © 2020-2023  润新知