bzoj 4337: BJOI2015 树的同构 树哈希

来源:互联网 发布:ipad福利软件 编辑:程序博客网 时间:2024/05/23 15:01

题意

树是一种很常见的数据结构。
我们把N个点,N-1条边的连通无向图称为树。
若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。
对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相
同,那么这两个树是同构的。也就是说,它们具有相同的形态。
现在,给你M个有根树,请你把它们按同构关系分成若干个等价类。
1 ≤ N, M ≤ 50。

分析

裸的树哈希。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef unsigned long long ull;const int N=55;const ull BASE=233333333;int n,m,cnt,last[N],root,f[N],size[N];struct edge{int to,next;bool del;}e[N*2];ull a[N],tmp[N],hash[N*2];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];e[cnt].del=0;last[u]=cnt;    e[++cnt].to=u;e[cnt].next=last[v];e[cnt].del=0;last[v]=cnt;}void get_root(int x,int fa){    size[x]=1;f[x]=0;    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa||e[i].del) continue;        get_root(e[i].to,x);        size[x]+=size[e[i].to];        f[x]=max(f[x],size[e[i].to]);    }    f[x]=max(f[x],n-size[x]);    if (!root||f[x]<f[root]) root=x;}void get_hash(int x,int fa){    for (int i=last[x];i;i=e[i].next)        if (e[i].to!=fa&&!e[i].del) get_hash(e[i].to,x);    int tot=0;    for (int i=last[x];i;i=e[i].next)        if (e[i].to!=fa&&!e[i].del) tmp[++tot]=hash[e[i].to];    sort(tmp+1,tmp+tot+1);    hash[x]=BASE;    for (int i=1;i<=tot;i++) (((hash[x]*=BASE)^=tmp[i])+=tmp[i])^=tmp[i];}int main(){    m=read();    for (int k=1;k<=m;k++)    {        n=read();        for (int j=1;j<=n+1;j++) last[j]=0;        cnt=1;        for (int j=1;j<=n;j++)        {            int x=read();            if (x) addedge(x,j);        }        root=0;        get_root(1,0);        int r1=0,r2=0;        for (int i=1;i<=n;i++)            if (f[i]==f[root]) r2=r1,r1=i;        if (r2)        {            for (int i=2;i<=cnt;i+=2)                if (e[i].to==r1&&e[i^1].to==r2||e[i].to==r2&&e[i^1].to==r1) {e[i].del=e[i^1].del=1;break;}            addedge(n+1,r1);addedge(n+1,r2);            root=n+1;        }        get_hash(root,0);        a[k]=hash[root];    }    for (int i=1;i<=m;i++)        for (int j=1;j<=i;j++)            if (a[i]==a[j])            {                printf("%d\n",j);                break;            }    return 0;}
原创粉丝点击