1. 程式人生 > >刷題總結——樹的同構(bzoj4337 樹上hash)

刷題總結——樹的同構(bzoj4337 樹上hash)

inline rime sin com amp const 註意 turn input

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解決樹的同構問題的模板題···

先說如何進行樹上hash,設f[i]為以i為節點的hash值,則

f[i]=sigma(f[j]*prime[j]) j為son[i]

其中prime為預處理出來的素數表···註意f[j]需要進行排序····

然後對於兩顆待判定的樹,將兩顆樹分別以樹上每一個節點為根節點求hash值··將根節點的hash值儲存起來排序然後兩顆樹一一比對··如果完全一樣則兩棵樹就一樣

代碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=55;
int hash[N][N],n,que[N];
int tot,fst[N],nxt[N*2
],go[N*2],f[N]; int prime[]={0,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,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317}; inline void comb(int a,int b) { nxt[++tot]=fst[a],fst[a]=tot,go[tot]=b; nxt[++tot]=fst[b],fst[b]=tot,go[tot]=a; } inline void dfs(int u,int fa) { unsigned int st[N];int tot=0; st[++tot]=1; for(int e=fst[u];e;e=nxt[e]) { int v=go[e];if(v==fa) continue; dfs(v,u); st[++tot]=f[v]; } f[u]=0;sort(st+1,st+tot+1); for(int i=1;i<=tot;i++) f[u]+=st[i]*prime[i]; } int main() { // freopen("a.in","r",stdin); scanf("%d",&n);int a,b; for(int i=1;i<=n;i++) { scanf("%d",&a); memset(fst,0,sizeof(fst));tot=0; for(int j=1;j<=a;j++) { scanf("%d",&b); if(b) comb(j,b); } for(int j=1;j<=a;j++) { dfs(j,0);hash[i][j]=f[j]; } sort(hash[i]+1,hash[i]+a+1); for(int j=1;j<=i;j++) { bool flag=true; for(int k=1;k<=a;k++) if(hash[j][k]!=hash[i][k]) { flag=false;break; } if(flag==true) { printf("%d\n",j); break; } } } return 0; }

刷題總結——樹的同構(bzoj4337 樹上hash)