树同构是树哈希与换根 dp 的结合。
树哈希是哈希中的一个种类,这里先给出哈希函数:
\[\operatorname{treehash}(u)=\sum \operatorname{xorshift}(\operatorname{treehash}(v)) \]这里使用 unsigned long long
的自然溢出特性代替取模。
我们设 \(g[u]\) 是以 \(u\) 为根的子树的 hash 值。
直接使用上式计算即可。
再设 \(f[u]\) 为以 \(u\) 为根的整棵树的 hash 值。
易知:\(f[u]= \operatorname{treehash}(f[fa] - \operatorname{xorshift(g[u])})+g[u]\)
贴个代码:
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
int rp;
const int N=1e3+10;
int g[N],f[N];
struct edge{
int v,next;
}edges[N*2];
int head[N],idx;
set<int>s[N];
int n;
void add_edge(int u,int v){
idx++;
edges[idx].v=v;
edges[idx].next=head[u];
head[u]=idx;
return;
}
int xor_shift(int x){
x^=rp;
x^=x<<13;
x^=x>>7;
x^=x<<17;
x^=rp;
return x;
}
void init(){
idx=0;
for(int i=1;i<=n;i++)head[i]=0;
return;
}
void get_hash_val(int u,int fa){
g[u]=1;
for(int i=head[u];i;i=edges[i].next){
int v=edges[i].v;
if(v==fa)continue;
get_hash_val(v,u);
g[u]+=xor_shift(g[v]);
}
return;
}
void dfs(int u,int fa){
if(fa==0){
f[u]=g[u];
}
else{
f[u]=xor_shift(f[fa]-xor_shift(g[u]))+g[u];
}
for(int i=head[u];i;i=edges[i].next){
int v=edges[i].v;
if(v==fa)continue;
dfs(v,u);
}
return;
}
signed main(){
std::ios::sync_with_stdio(false);
srand(time(NULL));
rp=rand();rp++;
int t;
cin>>t;
for(int i=1;i<=t;i++){
cin>>n;
init();
int root=0;
for(int j=1;j<=n;j++){
int x;
cin>>x;
if(x!=0){
add_edge(x,j);
add_edge(j,x);
}
else root=j;
}
assert(root);
get_hash_val(root,0);
dfs(root,0);
int ans=i;
for(int j=1;j<=n;j++)s[i].insert(f[j]);
for(int j=1;j<=n;j++){
for(int k=1;k<t;k++){
if(s[k].count(f[j])){
ans=min(k,ans);
}
}
}
cout<<ans<<endl;
}
return 0;
}
标签:同构,idx,int,long,哈希,root,operatorname
From: https://www.cnblogs.com/little-corn/p/18157421