luogu P5043 【模板】树同构([BJOI2015]树的同构)
https://www.luogu.com.cn/problem/P5043
突然发现之前自己的技能树点得有点乱
可以直接用最小表示法求出树的括号序列来判断是否同构
根节点取重心即可,如果有两个,取字典序更小的那个
时间复杂度\(O(n^2m)\)
code:
#include<bits/stdc++.h>
#define N 250
using namespace std;
int siz[N], msiz[N], n, t;
vector<int> g[N];
void findrt(int u, int fa) {
siz[u] = 1; msiz[u] = 0;
for(int v : g[u]) {
if(v == fa) continue;
findrt(v, u); siz[u] += siz[v];
msiz[u] = max(msiz[u], siz[v]);
}
msiz[u] = max(msiz[u], n - siz[u]);
}
string f[N], ls[N], ha[N];
void dfs(int u, int fa) {
f[u] = "0";
int gs = 0;
for(int v : g[u]) {
if(v == fa) continue;
dfs(v, u);
}
for(int v : g[u]) {
if(v == fa) continue;
ls[++ gs] = f[v];
}
sort(ls + 1, ls + 1 + gs);
for(int i = 1; i <= gs; i ++) f[u] = f[u] + ls[i];
f[u] = f[u] + "1";
}
int main() {
// freopen("a.out","w",stdout);
scanf("%d", &t);
for(int id = 1; id <= t; id ++) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) g[i].clear();
for(int i = 1; i <= n; i ++) {
int x;
scanf("%d", &x);
if(x) g[i].push_back(x), g[x].push_back(i);
}
findrt(1, 0);
int rt = 1;
for(int i = 1; i <= n; i ++) if(msiz[i] < msiz[rt]) rt = i;
ha[id] = "3";
for(int i = 1; i <= n; i ++) if(msiz[i] == msiz[rt]) {
dfs(i, 0);
ha[id] = min(ha[id], f[i]);
}
for(int i = 1; i <= id; i ++) if(ha[i] == ha[id]) {//printf("** %d %d\n", id, i);
printf("%d\n", i); break;
}
}
return 0;
}