luogu P5043

题目链接

题意

给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;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 993

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103856303