BZOJ4337 樹的同構(樹的重心+括號序列/雜湊)
阿新 • • 發佈:2018-12-13
【題目描述】
樹是一種很常見的資料結構。
我們把N個點,N-1條邊的連通無向圖稱為樹。
若將某個點作為根,從根開始遍歷,則其它的點都有一個前驅,這個樹就成為有根樹。
對於兩個樹T1和T2,如果能夠把樹T1的所有點重新標號,使得樹T1和樹T2完全相
同,那麼這兩個樹是同構的。也就是說,它們具有相同的形態。
現在,給你M個有根樹,請你把它們按同構關係分成若干個等價類。
【輸入格式】
第一行,一個整數M。
接下來M行,每行包含若干個整數,表示一個樹。第一個整數N表示點數。接下來N
個整數,依次表示編號為1到N的每個點的父親結點的編號。根節點父親結點編號為0。
【輸出格式】
輸出M行,每行一個整數,表示與每個樹同構的樹的最小編號。
【樣例輸入】
4
4 0 1 1 2
4 2 0 2 3
4 0 1 1 1
4 0 1 2 3
【樣例輸出】
1
1
3
1
【備註】
100% 的資料中,1 ≤ N, M ≤ 50。
【題目分析】
顯然,這個題可以dfs求每棵樹的雜湊然後判斷,這裡有一種更高階的做法,就是利用dfs序的改進版——括號序列。
因為這是無根樹,又因為一棵樹的重心最多隻有兩個,所以我們就以重心為樹的根,這樣樹高就有了保證,如果有兩個重心就跑兩遍,再按照字典序排序取字典序較小的那個。
【程式碼~】
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> using namespace std; const int MAXN=1e5+10; const int INF=0x3f3f3f3f; int Read() { int i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } int n,minn,m,cnt; int siz[MAXN],head[MAXN],maxx[MAXN]; int to[MAXN],nxt[MAXN]; string hash[MAXN],p[MAXN],ans[MAXN]; void add(int x,int y) { cnt++; nxt[cnt]=head[x]; head[x]=cnt; to[cnt]=y; } void dfs(int u,int fa) { int sum=0; for(int i=head[u];i!=-1;i=nxt[i]) { int v=to[i]; if(v!=fa) dfs(v,u); } for(int i=head[u];i!=-1;i=nxt[i]) { int v=to[i]; if(v!=fa) { p[++sum]=hash[v]; } } hash[u]='('; sort(p+1,p+sum+1); for(int i=1;i<=sum;++i) hash[u]+=p[i]; hash[u]+=')'; } void getroot(int u,int fa) { maxx[u]=0,siz[u]=1; for(int i=head[u];i!=-1;i=nxt[i]) { int v=to[i]; if(v!=fa) { getroot(v,u); siz[u]+=siz[v]; maxx[u]=max(maxx[u],siz[v]); } } maxx[u]=max(maxx[u],m-siz[u]); minn=min(minn,maxx[u]); } string getans() { string ret=""; m=Read(); memset(head,-1,sizeof(head)); for(int i=1;i<=m;++i) { int x=Read(); if(x) { add(x,i); add(i,x); } } minn=1<<30,getroot(1,0); for(int i=1;i<=m;++i) if(maxx[i]==minn) { dfs(i,0); ret=max(ret,hash[i]); } return ret; } int main() { n=Read(); for(int i=1;i<=n;++i) ans[i]=getans(); int j; for(int i=1;i<=n;++i) { for(j=1;j<i;++j) if(ans[i]==ans[j]) break; printf("%d\n",j); } return 0; }