BZOJ 4337: BJOI2015 树的同构 树hash

4337: BJOI2015 树的同构

题目连接:

http://www.lydsy.com/JudgeOnline/problem.php?id=4337

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。

题意

题解

从树的重心开始hash,因为重心最多两个。

然后找到树的最小表示就好了。

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 555;
int f[maxn],son[maxn],n,mx;
vector<int>E[maxn];
string h[maxn],h2[maxn],ha[maxn];
void getroot(int x,int fa)
{
    son[x]=1,f[x]=0;
    for(int i=0;i<E[x].size();i++)
    {
        int p=E[x][i];
        if(p==fa)continue;
        getroot(p,x);
        son[x]+=son[p];
        f[x]=max(f[x],son[p]);
    }
    f[x]=max(f[x],n-son[x]);
    mx=max(f[x],mx);
}
void init()
{
    for(int i=1;i<=n;i++)E[i].clear();
    mx=0;
    memset(f,0,sizeof(f));
    memset(son,0,sizeof(son));
}
void dfs(int x,int fa){
    h[x]="(";
    for(int i=0;i<E[x].size();i++){
        int v = E[x][i];
        if(v!=fa)dfs(v,x);
    }
    int now=0;
    for(int i=0;i<E[x].size();i++){
        int v = E[x][i];
        if(v!=fa)
            h2[now++]=h[v];
    }
    sort(h2,h2+now);
    for(int i=0;i<now;i++)
        h[x]+=h2[i];
    h[x]+=")";
}
string get()
{
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(x){
            E[x].push_back(i);
            E[i].push_back(x);
        }
    }
    getroot(1,0);
    string tmp = "";
    for(int i=1;i<=n;i++){
        if(f[i]==mx)
        {
            dfs(i,0);
            if(h[i]>tmp)tmp=h[i];
        }
    }
    return tmp;
}
int main()
{
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++)
        ha[i]=get();
    for(int i=1;i<=q;i++){
        for(int j=1;j<=i;j++){
            if(ha[i]==ha[j]){
                cout<<j<<endl;
                break;
            }
        }
    }
}
posted @ 2016-11-08 11:44  qscqesze  阅读(1809)  评论(1编辑  收藏  举报