题意
给m(m<=50)棵树,每棵树的节点<=50,问和每棵树同构的编号最小的树是哪一棵,每棵树的编号就是输入时的顺序.
解法
树hash:dfs的同时给每个节点计算一个hash值,然后最后就会有根节点的hash值,因为这种hash与选择哪个点为根关系很大,所以需要把每个点都当做根跑一边,然后得到关于一棵树的每个节点作为根的hash数组,为了比较两棵树是否同构,还需要将这个数组排个序,相当于一个最小表示法,这样就可以直接比较了.
注意
首先,对于dfs时应该是每个节点都要开一个记录儿子hash值的数组,我一开始用了一个全局数组记录,出现了混用,WA飞了.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353,step=2333;
const int maxn=55;
inline int read(){
char c=getchar();int t=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int m,n,rt;
struct edge{
int v,p;
}e[maxn<<1];
int h[maxn],cnt;
inline void add(int a,int b){
e[++cnt].p=h[a];
e[cnt].v=b;
h[a]=cnt;
e[++cnt].p=h[b];
e[cnt].v=a;
h[b]=cnt;
}
ll alfa[maxn],pos[maxn][maxn];
int dep[maxn];
void dfs(int u,int fa){
int tot=0;
ll ton[maxn];
for(int i=h[u];i;i=e[i].p){
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
ton[++tot]=alfa[v];//printf("%d %d %lld\n",u,v,alfa[v]);
}
sort(ton+1,ton+1+tot);
//for(int i=1;i<=tot;i++)printf("%lld ",ton[i]);
//puts("");
alfa[u]=1;
for(int i=1;i<=tot;i++){
alfa[u]=(alfa[u]*step%mod+ton[i])%mod;
}
alfa[u]=alfa[u]*step%mod;
}
int main(){
//freopen("5043.in","r",stdin);
//freopen("5043.out","w",stdout);
m=read();
for(int i=1;i<=m;i++){
memset(e,0,sizeof(e));cnt=0;
memset(h,0,sizeof(h));
int n=read();
for(int j=1;j<=n;j++){
int x=read();
if(x!=0){
add(x,j);
}
}
for(int j=1;j<=n;j++){memset(alfa,0,sizeof(alfa));
dfs(j,0);
// printf("%d %d %lld\n",i,j,alfa[j]);
pos[i][j]=alfa[j];
}
sort(pos[i]+1,pos[i]+1+n);
/*for(int j=1;j<=n;j++){
printf("%lld ",pos[i][j]);
}
puts("");*/
for(int j=1,k=0;j<=i;j++,k=0){
while(k<=n){if(pos[i][++k]!=pos[j][k])break;}
if(k>n){printf("%d\n",j);break;}
}
// memset(dep,0,sizeof(dep));
}
return 0;
}