BZOJ4337 树的同构(树的重心+括号序列/哈希)
【题目描述】
树是一种很常见的数据结构。
我们把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
【备注】
100% 的数据中,1 ≤ N, M ≤ 50。
【题目分析】
显然,这个题可以dfs求每棵树的哈希然后判断,这里有一种更高级的做法,就是利用dfs序的改进版——括号序列。
因为这是无根树,又因为一棵树的重心最多只有两个,所以我们就以重心为树的根,这样树高就有了保证,如果有两个重心就跑两遍,再按照字典序排序取字典序较小的那个。
【代码~】
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;
int Read()
{
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int n,minn,m,cnt;
int siz[MAXN],head[MAXN],maxx[MAXN];
int to[MAXN],nxt[MAXN];
string hash[MAXN],p[MAXN],ans[MAXN];
void add(int x,int y)
{
cnt++;
nxt[cnt]=head[x];
head[x]=cnt;
to[cnt]=y;
}
void dfs(int u,int fa)
{
int sum=0;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(v!=fa)
dfs(v,u);
}
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(v!=fa)
{
p[++sum]=hash[v];
}
}
hash[u]='(';
sort(p+1,p+sum+1);
for(int i=1;i<=sum;++i)
hash[u]+=p[i];
hash[u]+=')';
}
void getroot(int u,int fa)
{
maxx[u]=0,siz[u]=1;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(v!=fa)
{
getroot(v,u);
siz[u]+=siz[v];
maxx[u]=max(maxx[u],siz[v]);
}
}
maxx[u]=max(maxx[u],m-siz[u]);
minn=min(minn,maxx[u]);
}
string getans()
{
string ret="";
m=Read();
memset(head,-1,sizeof(head));
for(int i=1;i<=m;++i)
{
int x=Read();
if(x)
{
add(x,i);
add(i,x);
}
}
minn=1<<30,getroot(1,0);
for(int i=1;i<=m;++i)
if(maxx[i]==minn)
{
dfs(i,0);
ret=max(ret,hash[i]);
}
return ret;
}
int main()
{
n=Read();
for(int i=1;i<=n;++i)
ans[i]=getans();
int j;
for(int i=1;i<=n;++i)
{
for(j=1;j<i;++j)
if(ans[i]==ans[j])
break;
printf("%d\n",j);
}
return 0;
}