zoukankan      html  css  js  c++  java
  • BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构

    题目连接:

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

    Description

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

    Input

    第一行,一个整数M。
    接下来M行,每行包含若干个整数,表示一个树。第一个整数N表示点数。接下来N
    个整数,依次表示编号为1到N的每个点的父亲结点的编号。根节点父亲结点编号为0。

    Output

    输出M行,每行一个整数,表示与每个树同构的树的最小编号。

    Sample Input

    4

    4 0 1 1 2

    4 2 0 2 3

    4 0 1 1 1

    4 0 1 2 3

    Sample Output

    1

    1

    3

    1

    Hint

    【样例解释】

    编号为1, 2, 4 的树是同构的。编号为3 的树只与它自身同构。

    100% 的数据中,1 ≤ N, M ≤ 50。

    题意

    题解

    从树的重心开始hash,因为重心最多两个。

    然后找到树的最小表示就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 555;
    int f[maxn],son[maxn],n,mx;
    vector<int>E[maxn];
    string h[maxn],h2[maxn],ha[maxn];
    void getroot(int x,int fa)
    {
        son[x]=1,f[x]=0;
        for(int i=0;i<E[x].size();i++)
        {
            int p=E[x][i];
            if(p==fa)continue;
            getroot(p,x);
            son[x]+=son[p];
            f[x]=max(f[x],son[p]);
        }
        f[x]=max(f[x],n-son[x]);
        mx=max(f[x],mx);
    }
    void init()
    {
        for(int i=1;i<=n;i++)E[i].clear();
        mx=0;
        memset(f,0,sizeof(f));
        memset(son,0,sizeof(son));
    }
    void dfs(int x,int fa){
        h[x]="(";
        for(int i=0;i<E[x].size();i++){
            int v = E[x][i];
            if(v!=fa)dfs(v,x);
        }
        int now=0;
        for(int i=0;i<E[x].size();i++){
            int v = E[x][i];
            if(v!=fa)
                h2[now++]=h[v];
        }
        sort(h2,h2+now);
        for(int i=0;i<now;i++)
            h[x]+=h2[i];
        h[x]+=")";
    }
    string get()
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++){
            int x;scanf("%d",&x);
            if(x){
                E[x].push_back(i);
                E[i].push_back(x);
            }
        }
        getroot(1,0);
        string tmp = "";
        for(int i=1;i<=n;i++){
            if(f[i]==mx)
            {
                dfs(i,0);
                if(h[i]>tmp)tmp=h[i];
            }
        }
        return tmp;
    }
    int main()
    {
        int q;scanf("%d",&q);
        for(int i=1;i<=q;i++)
            ha[i]=get();
        for(int i=1;i<=q;i++){
            for(int j=1;j<=i;j++){
                if(ha[i]==ha[j]){
                    cout<<j<<endl;
                    break;
                }
            }
        }
    }
  • 相关阅读:
    JAVA中的super和this关键字的使用
    JAVA中类以及成员变量和成员方法的修饰符的总结
    JAVA中的抽象类和接口
    JAVA对数据库进行操作,实现数据库中数据的插入,查询,更改,删除操作
    完整日期正则表达式
    2017实习【Java研发】面经
    MySQL事务及隔离级别(读书小结)
    Java类编译、加载、和执行机制
    JVM内存回收机制
    Centos6.5的MySQL5.7.15二进制源码单机版安装
  • 原文地址:https://www.cnblogs.com/qscqesze/p/6042436.html
Copyright © 2011-2022 走看看