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;
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM