luogu P5043 【模板】树同构 hash 最小表示法

LINK:模板 树同构

题目说的很迷 给了一棵有根树 但是重新标号 言外之意还是一棵无根树 然后要求判断是否重构。

由于时无根的 所以一个比较显然的想法暴力枚举根。

然后做树hash或者树的最小表示法。

前者做一次时n^2logn的 而后者则是严格的n^2logn的。

这样加上暴力枚举根就是n^3logn了。

最后我们将这些东西再sort一下和其他的树做对比 如果所有的都完全一致那么说明时同构的。

算法正确性 首先完全一样的树 再做树hash或者最小表示法时 得到的东西必然一样。

这个可以利用递归证明 经过再dfs中的sort可以发现变成唯一指定了。

考虑一个更优的做法 可以发现树的中心唯一/唯二 但是两个中心做hash却不尽相同。

可以对这两个点单独做 这样最后再对比即可。

这样就是n^2logn了。

最后 注意hash函数的设定 我第一次设的 竟然直接hash冲突了...

const int MAXN=55,cc0=19260817,cc1=114514;
int n,op,maxx;
int ha1[MAXN],ha2[MAXN],son[MAXN],sz[MAXN],s1,s2;
vector<int>g[MAXN][MAXN];
inline int dfs(int x,int fa)
{
	ll h=cc0;
	int q[MAXN],top=0;
	for(ui i=0;i<g[op][x].size();++i)
	{
		int tn=g[op][x][i];
		if(tn==fa)continue;
		q[++top]=dfs(tn,x);
	}
	sort(q+1,q+1+top);
	rep(1,top,i)h=(h*q[i])%mod;
	return (h*P+cc1)%mod;
}
inline void get_root(int x,int fa)
{
	sz[x]=1;son[x]=0;
	for(ui i=0;i<g[op][x].size();++i)
	{
		int tn=g[op][x][i];
		if(tn==fa)continue;
		get_root(tn,x);
		sz[x]+=sz[tn];
		son[x]=max(son[x],sz[tn]);
	}
	son[x]=max(son[x],maxx-sz[x]);
	if(son[s1]==son[x])s2=x;
	if(son[s1]>son[x])s1=x,s2=0;
}
int main()
{
	freopen("1.in","r",stdin);
	get(n);son[0]=INF; 
	rep(1,n,i)
	{
		int get(x),root;
		rep(1,x,j){int get(y);if(!y)root=j;else g[i][y].pb(j),g[i][j].pb(y);}
		maxx=x;op=i;s1=s2=0;get_root(root,0);ha1[i]=dfs(s1,0);if(s2)ha2[i]=dfs(s2,0);else ha2[i]=-i;
	}
	rep(1,n,i)rep(1,n,j)if(ha1[i]==ha1[j]||ha1[i]==ha2[j]){put(j);break;}
	return 0;
}
posted @ 2020-04-16 14:22  chdy  阅读(118)  评论(0编辑  收藏  举报