BZOJ4337 [BJOI2015] 樹的同構 樹上雜湊

~hsm~發表於2019-01-27

題目

BZOJ 4337
luogu 5043

題解

這道題讓我們把樹的結構歸類,自然而然就想到了雜湊,我們對這整顆樹雜湊一遍,然後判同構就只需要找雜湊值一樣的樹就可以了。
綜上所述,這是一道樹上雜湊模板題。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e3+10;
template<typename T>inline void read(T &x)
{
	T s=0,f=1;	static char ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (!isdigit(ch)) { f=-1; ch=getchar(); }
	while (isdigit(ch)) s=(s<<1)+(s<<3)+(ch^48), ch=getchar();
	x=s*f;
}
ll ans[maxn][maxn],head[maxn],ver[maxn],Next[maxn],tot;
inline void add(int x,int y)
{
    ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}
inline ll Hash(int x,int f)//樹雜湊
{
    ll q[maxn],ans=maxn,top=0;
    for (int i=head[x];i;i=Next[i])//遍歷所以子節點
    	if (ver[i]!=f)//不能再次遍歷以遍歷的點,即x的父親
    		q[++top]=Hash(ver[i],x);
    sort(q+1,q+top+1);//把雜湊打得更亂
    for (int i=1;i<=top;++i)//對x點計算雜湊值
    	ans=ans*2333+q[i];
    return ans*2333+maxn+1;
}
int main()
{
    static int m;read(m);
    for(int i=1;i<=m;++i)
    {
        tot=0;
		memset(head,0,sizeof(head));
        static int n;read(n);
        for (int j=1;j<=n;++j)
        {
            static int x;read(x);
            if (x)
				add(x,j),add(j,x);
        }
        for (int j=1;j<=n;++j)
        	ans[i][j]=Hash(j,0);//樹雜湊
        sort(ans[i]+1,ans[i]+n+1);
        for (int j=1,k=0;j<=i;++j)
        {
            while (k<=n)   
				if (ans[i][++k]!=ans[j][k]) break;//找同構
            if (k>n)
			{
				printf("%d\n",j);
				break;
			}//找到同構就輸出
        }
    }
    return 0;
}

相關文章