【题目】
Description
树是一种很常见的数据结构。
我们把 n n n 个点, n − 1 n-1 n−1 条边的连通无向图称为树。
若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。
对于两个树 t 1 t1 t1 和 t 2 t2 t2,如果能够把树 t 1 t1 t1 的所有点重新标号,使得树 t 1 t1 t1 和树 t 2 t2 t2 完全相同,那么这两个树是同构的。也就是说,它们具有相同的形态。
现在,给你 m m m 个有根树,请你把它们按同构关系分成若干个等价类。
Input
第一行,一个整数 m m m。
接下来 m m m 行,每行包含若干个整数,表示一个树。第一个整数 n n n 表示点数。接下来 n n n 个整数,依次表示编号为 1 1 1 到 n n n 的每个点的父亲结点的编号。根节点父亲结点编号为 0 0 0。
Output
输出 m m 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
1, 2, 4
1,2,4 的树是同构的。编号为
3
3
3 的树只与它自身同构。
100
%
100\%
100% 的数据中,
1
1
1 ≤
n
,
m
n, m
n,m ≤
50
50
50。
【分析】
首先来说一下括号序列吧
考虑 d f s dfs dfs 序,在 d f s dfs dfs 完一个点的时候,我们同样把他加入序列,这样得到的序列叫做括号序列。
对于一棵有根树,如果子节点有序,那么这棵树唯一对应着一个括号序列。
那么对于这道题,其实只用找到括号序列就行了
现在又有两个问题:
- 对于两棵树,如果选的根不一样,就算结构相同,括号序列不一定相同
- 对于两棵树,如果选的根相同,但若 d f s dfs dfs 的顺序不同,得到的括号序列也不一定相同
所以现在的问题就是如何找根以及如何进行 d f s dfs dfs
对于找根,由于一颗是树的重心至多两个,而若两棵树同构,重心肯定是一样的,所以就从重心开始 d f s dfs dfs
对于 d f s dfs dfs,每次 d f s dfs dfs 到一个节点,都把它的所有子树的括号序列排序,然后按照顺序加进根的括号序列
听说用
v
e
c
t
o
r
vector
vector 会好一点,不过直接用
s
t
r
i
n
g
string
string 也可以过,毕竟 n,m 最大才 50
【代码】
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define N 1005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,t,num;
int Max[N],size[N];
int first[N],v[N],nxt[N];
string rec[N],brackets[N];
void add(int x,int y)
{
t++;
nxt[t]=first[x];
first[x]=t;
v[t]=y;
}
void find(int x,int father)
{
int i,j;
Max[x]=0,size[x]=1;
for(i=first[x];i;i=nxt[i])
{
j=v[i];
if(j!=father)
{
find(j,x);
size[x]+=size[j];
Max[x]=max(Max[x],size[j]);
}
}
Max[x]=max(Max[x],n-size[x]);
num=min(num,Max[x]);
}
void dfs(int x,int father)
{
int i,j,num=0;
string temp[N];
brackets[x]='(';
for(i=first[x];i;i=nxt[i])
{
j=v[i];
if(j!=father)
{
dfs(j,x);
temp[++num]=brackets[j];
}
}
sort(temp+1,temp+num+1);
for(i=1;i<=num;++i)
brackets[x]+=temp[i];
brackets[x]+=')';
}
int main()
{
int i,j,x;
scanf("%d",&m);
for(i=1;i<=m;++i)
{
t=0;
scanf("%d",&n);
memset(first,0,sizeof(first));
for(j=1;j<=n;++j)
{
scanf("%d",&x);
if(x) add(x,j),add(j,x);
}
num=inf,find(1,0);
string s=" ";
for(j=1;j<=n;++j)
{
if(Max[j]==num)
{
dfs(j,0);
if(s==" "||s>brackets[j])
s=brackets[j];
}
}
rec[i]=s;
for(j=1;j<=i;++j)
{
if(s==rec[j])
{
printf("%d\n",j);
break;
}
}
}
return 0;
}