【Hash】BZOJ4337(BJOI2015)[树的同构]题解

题目概述

给出 m 棵无根树,求每棵树 i 的同构的树(长得一样)的最小编号。

解题报告

题目骗人QAQ,明明是无根树,还搞个根节点。怎么判断同构?Hash大法好!

比较好的Hash方法是给每个儿子都对应一个素数(可以提前打表搞出 50 个素数),需要注意的是要将儿子按照权值排序,这样才能才能正确判断树的同构。

示例程序

#include
#include
#include
using namespace std;
typedef unsigned long long ULL;
const int maxn=50,maxm=50,Base=23333;
const int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229};

int m,ro,n[maxm+5];ULL ha[maxm+5][maxn+5];
int E,lnk[maxn*2+5],nxt[maxn*2+5],son[maxn*2+5];

inline void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}
ULL Dfs(int x,int fa=0)
{
    int tot=0;ULL now[maxn+5],v=Base;
    for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa) now[tot++]=Dfs(son[j],x);
    sort(now,now+tot);for (int i=0;ireturn v;
}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&n[i]);E=0;memset(lnk,0,sizeof(lnk));
        for (int j=1,x;j<=n[i];j++)
            {scanf("%d",&x);if (x) Add(x,j),Add(j,x);}
        for (int j=1;j<=n[i];j++) ha[i][j]=Dfs(j);sort(ha[i]+1,ha[i]+1+n[i]);
        for (int j=1,k;j<=i;j++) if (n[i]==n[j])
        {
            for (k=1;k<=n[i];k++) if (ha[i][k]!=ha[j][k]) break;
            if (k>n[i]) {printf("%d\n",j);break;}
        }
    }
    return 0;
}

你可能感兴趣的:(BZOJ题解,哈希)