BJOI2015-数的同构(树的哈希)

树是一种很常见的数据结构。 我们把N个点,N-1条边的连通无向图称为树。 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。 对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相 同,那么这两个树是同构的。也就是说,它们具有相同的形态。 现在,给你M个有根树,请你把它们按同构关系分成若干个等价类。
输入
第一行,一个整数M。 接下来M行,每行包含若干个整数,表示一个树。第一个整数N表示点数。接下来N 个整数,依次表示编号为1到N的每个点的父亲结点的编号。根节点父亲结点编号为0。
输出
输出M行,每行一个整数,表示与每个树同构的树的最小编号。
样例输入
4
4 0 1 1 2
4 2 0 2 3
4 0 1 1 1
4 0 1 2 3
样例输出
1
1
3
1
提示
【样例解释】
编号为1, 2, 4 的树是同构的。编号为3 的树只与它自身同构。
100% 的数据中,1 ≤ N, M ≤ 50。

很简单的hash

直接暴力就可以了

只要将每一颗子树的hash值排个序,逐一比较就可以了

那我们来考虑点别的

如果n,m大小是1e5呢?

那也不难,

我们只需要找到每个树的中心

从重心来hash就可以了

#include<bits/stdc++.h>
#define uint unsigned int 
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229};
int adj[200],nxt[200],to[200],m,n,d[200],cnt;
uint hash[100][100];
inline void addedge(int u,int v)
{
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u;
}
inline uint hashin(int u,int fa)
{
    int nu=0;
    uint a[55],k=1;
    for(int i=adj[u];i;i=nxt[i])
    {
        if(to[i]!=fa) a[++nu]=hashin(to[i],u);
    }
    sort(a+1,a+nu+1);
    for(int i=1;i<=nu;i++)
    {
        k=k*409+a[i]*p[i];
    }
    return k;
}
int main(){
    m=read();
    for(int i=1;i<=m;i++)
    {
        cnt=0;
        memset(adj,0,sizeof(adj));
        memset(to,0,sizeof(adj));
        memset(nxt,0,sizeof(adj));
        d[i]=read();
        int x;
        for(int j=1;j<=d[i];j++)
        {
            x=read();
            if(x)
            addedge(x,j);
        }
        for(int j=1;j<=d[i];j++)
        {
            hash[i][j]=hashin(j,0);
        }
        sort(hash[i]+1,hash[i]+d[i]+1);
        for(int j=1;j<=i;j++)
        {
            if(d[i]==d[j])
            {
                bool iv=0;
                for(int k=1;k<=d[i];k++) if(hash[i][k]!=hash[j][k]) {iv=1;break;}
                if(!iv) {cout<<j<<'\n';break;}
            }
        }
    }
    return 0;
}
posted @ 2018-10-07 10:19  Stargazer_cykoi  阅读(169)  评论(0编辑  收藏  举报