【树hs】[BJOI2015]树的同构

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

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

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

样例一
input

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

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

限制与约定
对于100%的数据,1≤N,M≤501≤N,M≤50
时间限制:1s1s
空间限制:256MB
T

这道题是树hs裸题,树hs的思路就是,先把每个节点的点权赋为1,然后父节点累加子节点平方和自己的值向上返回,

就是一个递归的过程,然后自然溢出

但是每个树的根节点可能会不同,所以我们要有对于每个树选根的唯一标准

对,就是树重心,一个树可能有多个重心,那么我们只需要一个超级原点就ok 了

最后比较超级原点的hs值,就能知道是否同构

有一点玄学的地方,就是用seed的方式过不了,也不知道是为什么

 1 #include<bits/stdc++.h>
 2 #define N 100
 3 #define clear(a,val) memset(a,val,sizeof(a))
 4 using namespace std;
 5 typedef unsigned long long ult;
 6 int n,m,f,cnt=1,pp;
 7 int head[N],nxt[N*2],to[N*2],size[N],ans[N];
 8 ult vv[N],val[N];
 9 inline void add(int u,int v)
10     {nxt[cnt]=head[u],to[cnt]=v,head[u]=cnt++;}
11 inline void cl(){
12     clear(size,0),clear(ans,0),clear(head,-1),cnt=1,pp=0;
13 }
14 int dfs(int now,int fa)
15 {
16     size[now]=1;int ma=-1;
17     for(int i=head[now];i!=-1;i=nxt[i])
18     {
19         int t=to[i];
20         if(t==fa)continue;
21         size[now]+=dfs(t,now);
22         ma=max(ma,size[t]);
23     }
24     ma=max(ma,n-size[now]);
25     if(ma<=(n>>1))ans[++pp]=now;
26     return size[now];
27 }
28 inline void weigh()
29 {
30     dfs(1,-1);
31     for(int i=1;i<=pp;i++)
32         add(n+1,ans[i]);
33 }
34 ult cal(int now,int fa)
35 {
36     vv[now]=1;
37     for(int i=head[now];i!=-1;i=nxt[i])
38     {
39         int t=to[i];
40         if(t==fa)continue;
41         vv[now]+=cal(t,now);
42     }
43     return vv[now]*vv[now];
44 }
45 inline void init_build_weigh_solve()
46 {
47     clear(head,-1);
48     scanf("%d",&m);
49     for(int i=1;i<=m;i++)
50     {
51         cl();
52         scanf("%d",&n);
53         for(int j=1;j<=n;j++)
54         {
55             scanf("%d",&f);
56             if(f==0)continue;
57             else add(f,j),add(j,f);
58         }
59         weigh();
60         val[i]=cal(n+1,-1);
61     }
62     for(int i=1;i<=m;i++)
63     {
64         for(int j=1;j<=i;j++)
65         {
66             if(val[i]==val[j])
67             {
68                 printf("%d\n",j);
69                 break;
70             }
71         }
72     }
73 }
74 int main()
75 {
76     init_build_weigh_solve();
77     return 0;
78 }

 

posted @ 2019-01-01 11:20  浅夜_MISAKI  阅读(213)  评论(0编辑  收藏  举报