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

来源:互联网 发布:cad制图机械软件 编辑:程序博客网 时间:2024/05/18 21:12

题目概述

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

解题报告

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

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

示例程序

#include<cstdio>#include<cstring>#include<algorithm>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;i<tot;i++) v=v*Base+now[i]*p[i];return 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;}
原创粉丝点击