背景:
这是模板?
题目传送门:
https://www.luogu.org/problemnew/show/P5043
题意:
给
m
m
m棵树,判断这些树编号最小的同构树(重新编号后两棵树完全一样)。
思路:
考虑树上的
h
a
s
h
hash
hash。
我们可以认为若从任意一点开始所得到的
h
a
s
h
hash
hash值一样,则两棵树相同。
有人会问,若两棵树刚好左右相反怎么办(此时它们同构)。
我们在做的时候按照
h
a
s
h
hash
hash值排序不就避免了左右的问题了吗。
时间复杂度:
Θ
(
n
m
2
)
\Theta(nm^2)
Θ(nm2)。
据说比较重心会降到
Θ
(
m
n
)
\Theta(mn)
Θ(mn),但我怒刷
1
+
1+
1+版都无法调出 (肯定是我太菜) 。
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define base 13331
typedef unsigned long long LLu;
using namespace std;
int m,len;
int n[110],last[110];
LLu ans[110][110];
struct node{int x,y,next;} a[110];
void clear()
{
len=0;
memset(last,0,sizeof(last));
}
void ins(int x,int y)
{
a[++len]=(node){x,y,last[x]}; last[x]=len;
}
LLu dfs(int x,int fa)
{
vector<LLu> que;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
que.push_back(dfs(y,x));
}
sort(que.begin(),que.end());
LLu tmp=0;
for(int i=0;i<que.size();i++)
tmp=tmp*base+que[i];
return tmp*base+1;
}
bool check(int x,int y)
{
if(n[x]!=n[y]) return false;
for(int i=1;i<=n[x];i++)
if(ans[x][i]!=ans[y][i]) return false;
return true;
}
int main()
{
int x;
scanf("%d",&m);
for(int k=1;k<=m;k++)
{
clear();
scanf("%d",&n[k]);
for(int i=1;i<=n[k];i++)
{
scanf("%d",&x);
if(x) ins(x,i),ins(i,x);
}
for(int i=1;i<=n[k];i++)
ans[k][i]=dfs(i,0);
sort(ans[k]+1,ans[k]+n[k]+1);
for(int i=1;i<=k;i++)
if(check(i,k)) {printf("%d\n",i);break;}
}
}