BZOJ4337:[BJOI2015]树的同构(树hash)

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。

Solution

树hash,x的子树计算方法为$\sum hash[i]*val[i]$,其中hash[i]表示的是x的儿子的第i大的哈希值,val[i]是随机的一组很大的数。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<map>
 5 #include<algorithm>
 6 #define LL long long
 7 #define MOD (998244353)
 8 using namespace std;
 9 
10 struct Edge{int to,next;}edge[201];
11 LL T,n,x,ans,hash[101],val[101];
12 int head[101],num_edge;
13 map<LL,LL>Map;
14 
15 void add(int u,int v)
16 {
17     edge[++num_edge].to=v;
18     edge[num_edge].next=head[u];
19     head[u]=num_edge;
20 }
21 
22 void Dfs(int x,int fa)
23 {
24     LL q[101],tot=0;
25     hash[x]=0;
26     for (int i=head[x]; i; i=edge[i].next)
27         if (edge[i].to!=fa)
28             Dfs(edge[i].to,x),q[++tot]=hash[edge[i].to];
29     if (tot==0){hash[x]=1; return;}
30     sort(q+1,q+tot+1);
31     for (int i=1; i<=tot; ++i)
32         hash[x]=(hash[x]+q[i]*val[i])%MOD;
33 } 
34 
35 int main()
36 {
37     for (int i=1; i<=50; ++i)
38         val[i]=rand()*233473ll+rand()*19260817ll+rand();
39     scanf("%d",&T);
40     for (int t=1; t<=T; ++t)
41     {
42         scanf("%d",&n);
43         memset(head,0,sizeof(head)); num_edge=0;
44         for (int i=1; i<=n; ++i)
45         {
46             scanf("%d",&x);
47             if (!x) continue;
48             add(x,i), add(i,x);
49         }
50         ans=233;
51         for (int i=1; i<=n; ++i) 
52         {
53             Dfs(i,-1);
54             if (!Map[hash[i]]) Map[hash[i]]=t;
55             else Map[hash[i]]=min(Map[hash[i]],(LL)t);
56             ans=min(ans,Map[hash[i]]);
57         }
58         printf("%lld\n",ans);
59     }
60 }
posted @ 2018-08-29 08:55  Refun  阅读(237)  评论(0编辑  收藏  举报