1. 程式人生 > >bzoj 4337[BJOI2015]樹的同構 - 括號序列

bzoj 4337[BJOI2015]樹的同構 - 括號序列

con roo n-1 nbsp IT turn 樹的同構 memory style

4337: BJOI2015 樹的同構

Time Limit: 10 Sec Memory Limit: 256 MB

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。 對於一顆有根樹,可以用括號序列唯一的表示 將所有兒子的子樹的括號序列按從小到大排序,在最外面再用一個括號括起來 就是這顆子樹的括號序列。 一顆無根樹的重心最多有兩個,我們以重心為根,取括號序列更大的一個就可以一一對應了
技術分享圖片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #define LL long long
  6 
  7 using namespace std;
  8 
  9 const int MAXN = 60, MAXM = 60;
 10 
 11 int N, M;
 12 
 13 int size[MAXN];
 14 int head[MAXN];
 15 int vis[MAXN];
16 int cnt = 0; 17 18 inline LL read() 19 { 20 LL x = 0, w = 1; char ch = 0; 21 while(ch < 0 || ch > 9) { 22 if(ch == -) { 23 w = -1; 24 } 25 ch = getchar(); 26 } 27 while(ch >= 0 && ch <= 9) { 28 x = x * 10 + ch - 0; 29 ch = getchar(); 30 } 31 return x * w; 32 } 33 34 struct edge { 35 int v; 36 int next; 37 } g[MAXN * MAXN]; 38 39 int f[MAXN]; 40 int mx = 0; 41 42 string h[MAXM]; 43 void addedge(int u, int v) 44 { 45 g[++cnt].v = v; 46 g[cnt].next = head[u]; 47 head[u] = cnt; 48 } 49 50 void getroot(int x) 51 { 52 vis[x] = 1; 53 int minn = 0; 54 size[x] = 1; 55 for(int j = head[x]; j; j = g[j].next) { 56 int to = g[j].v; 57 if(!vis[to]) { 58 getroot(to); 59 size[x] += size[to]; 60 } 61 minn = max(size[to], minn); 62 } 63 minn = max(minn, N - size[x]); 64 f[x] = minn; 65 mx = min(minn, mx); 66 } 67 68 string DFS(int x) 69 { 70 // cout<<x<<endl; 71 vis[x] = 1; 72 int tot = 0; 73 string t[MAXN]; 74 string temp = ""; 75 temp += "("; 76 for(int j = head[x]; j; j = g[j].next) { 77 int to = g[j].v; 78 if(!vis[to]) { 79 t[tot++] = DFS(to); 80 } 81 } 82 sort(t, t + tot); 83 for(int i = 0; i < tot; i++) { 84 temp += t[i]; 85 } 86 temp += ")"; 87 return temp; 88 } 89 90 int main() 91 { 92 M = read(); 93 for(int i = 1; i <= M; i++) { 94 N = read(); 95 cnt = 0; 96 memset(head, 0, sizeof head); 97 memset(f, 0, sizeof f); 98 memset(vis, 0, sizeof vis); 99 memset(size, 0, sizeof size); 100 for(int j = 1; j <= N; j++) { 101 int l = read(); 102 if(l) { 103 addedge(j, l); 104 addedge(l, j); 105 } 106 } 107 mx = 1e9; 108 getroot(1); 109 for(int j = 1; j <= N; j++) { 110 //cout<<f[j]<<" "; 111 if(f[j] == mx) { 112 memset(vis, 0, sizeof vis); 113 h[i] = max(h[i], DFS(j)); 114 } 115 } 116 } 117 for(int i = 1; i <= M; i++) { 118 for(int j = 1; j <= i; j++) { 119 if(h[j] == h[i]) { 120 printf("%d\n", j); 121 break; 122 } 123 } 124 } 125 return 0; 126 } 127 128 /* 129 130 7 131 6 0 1 5 1 1 5 132 6 2 4 4 0 4 1 133 6 0 1 6 1 3 1 134 6 6 0 1 2 2 2 135 6 5 5 0 6 3 2 136 6 0 6 2 6 3 1 137 6 2 6 2 5 3 0 138 139 140 141 */
View Code

bzoj 4337[BJOI2015]樹的同構 - 括號序列