luogu P5043 【模板】树同构([BJOI2015]树的同构)

本文介绍了一种使用Hash算法来判断多棵树是否同构的方法。通过从任意节点开始计算Hash值,并对所有子树的Hash值进行排序,可以有效地解决树的同构问题。时间复杂度为Θ(nm^2),适用于需要快速判断树结构相似性的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

这是模板?

题目传送门:

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;}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值