树同构

link

树同构是树哈希与换根 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;
}
posted @ 2024-04-25 12:56  Little_corn  阅读(21)  评论(0编辑  收藏  举报