zoukankan      html  css  js  c++  java
  • BZOJ4337:[BJOI2015]树的同构——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4337

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

    Q:如何树哈希啊。

    A:网上也没有讲解啊,不如看看代码理解一下吧……我就是这么干的。

    代码抄自:https://blog.csdn.net/CHNWJD/article/details/78264934当然是没有讲解的。

    要注意dfs里的ans一定要有初值!

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ll;
    const int N=51;
    const int B=911;
    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};
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int to,nxt;
    }e[N*2];
    int n[N],m,cnt,head[N];
    ll ha[N][N];
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    int dfs(int u,int fa){
        ll num[N],ans=B;int tot=0;
        for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        num[++tot]=dfs(v,u);
        }
        sort(num+1,num+tot+1);
        for(int i=1;i<=tot;i++)ans=ans*B+num[i]*p[i];
        return ans;
    }
    int main(){
        m=read();
        for(int i=1;i<=m;i++){
        n[i]=read();cnt=0;
        memset(head,0,sizeof(head));
        for(int j=1;j<=n[i];j++){
            int v=read();
            if(v)add(j,v),add(v,j);
        }
        for(int j=1;j<=n[i];j++)ha[i][j]=dfs(j,0);
        sort(ha[i]+1,ha[i]+n[i]+1);
        bool flag=0;
        for(int j=1;j<=i&&!flag;j++)
            if(n[i]==n[j])
            for(int k=1;k<=n[i];k++){
                if(ha[i][k]!=ha[j][k])break;
                if(k==n[i]){
                printf("%d
    ",j);
                flag=1;
                }
            }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Problem S: 分数类的模板数组类
    Problem E: 向量的运算
    Problem D: 强悍的矩阵运算来了
    Problem C: Person类与Student类的关系
    Problem B: 还会用继承吗?
    Problem A: 求个最大值
    Problem B: 数组类(II)
    树的直径题集
    LCA题集
    线段树总结
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9168941.html
Copyright © 2011-2022 走看看