bzoj 4337[BJOI2015]树的同构 - 括号序列

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

 

 
 
 
posted @ 2018-03-18 22:34  大财主  阅读(286)  评论(0编辑  收藏  举报