P5043 【模板】树同构([BJOI2015]树的同构)
题意:输出与第i棵树同构的树的最小编号
题解:树hash或者最小表示法
树hash,有根树直接从根结点开始hash即可,对于无根树,由于每棵树的重心最多有两个,所以找到重心当作根节点开始hash即可。
我这里采用的hash方程为
sort(g.begin(),g.end());
for(int i=0;i<g.size();i++){
ac[u]=(ac[u]*base%mod+g[i])%mod;
}
ac[u]=(ac[u]*siz[u])%mod;
完整代码
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
const int maxn=105;
const int inf=1e9+5;
const int mod=23333;
const int base=233;
struct edge{
int fr;
int to;
int nex;
}e[maxn<<1];
int maxsiz,n,cnt,head[maxn],rt[maxn],siz[maxn],ans[maxn],sonsiz[maxn],ac[maxn];
void adde(int x,int y){
e[cnt].fr=x;
e[cnt].to=y;
e[cnt].nex=head[x];
head[x]=cnt++;
}
void dfs(int u,int f){
siz[u]=1;
int maxx=0;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(f==v)continue;
dfs(v,u);
siz[u]+=siz[v];
maxx=max(maxx,siz[v]);
}
maxx=max(maxx,n-siz[u]);
sonsiz[u]=maxx;
maxsiz=min(maxsiz,maxx);
}
int sol(int u,int f){
ac[u]=1;
vector<int>g;
siz[u]=1;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v==f)continue;
sol(v,u);
siz[u]+=siz[v];
g.push_back(ac[v]);
}
sort(g.begin(),g.end());
for(int i=0;i<g.size();i++){
ac[u]=(ac[u]*base%mod+g[i])%mod;
}
ac[u]=(ac[u]*siz[u])%mod;
return ac[u];
}
int main(){
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&n);
maxsiz=n+1;
cnt=0;
for(int j=1;j<=n;j++)head[j]=-1;
for(int j=1;j<=n;j++){
int f;
scanf("%d",&f);
if(f){
adde(j,f);
adde(f,j);
}
}
dfs(1,0);
ans[i]=inf;
for(int j=1;j<=n;j++){
if(sonsiz[j]==maxsiz){
ans[i]=min(ans[i],sol(j,0));
}
}
for(int j=1;j<=i;j++){
if(ans[j]==ans[i]){
printf("%d\n",j);
break;
}
}
}
return 0;
}
最小表示法(待补)