题意
对于两个树 T 1 T_1 T1 和 T 2 T_2 T2,如果能够把树 T 1 T_1 T1 的所有点重新标号,使得树 T 1 T_1 T1 和树 完 T 2 T_2 T2 全相同,那么这两个树是同构的。给你多棵树,输出与当前树同构的最小下标。
分析
对树搜重心,使用
f
[
u
]
=
∑
v
∈
s
o
n
(
u
)
f
[
v
]
+
p
[
s
z
[
v
]
]
f[u]=\sum_{v\in son(u)}f[v]+p[sz[v]]
f[u]=∑v∈son(u)f[v]+p[sz[v]] 计算当前树的
h
a
s
h
hash
hash值
p
p
p是质数数组,在最开始
r
a
n
d
o
m
_
s
h
u
f
f
l
e
random\_shuffle
random_shuffle进行随机排序。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = N * 2, inf = 1e8;
int p[70] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,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};
int m, n;
int sz[N], w[N], rt1, rt2;
ull f[N];
vector<int> G[N];
vector<ull> Hash[N];
void get_root(int x, int fa){ // 搜重心
sz[x] = 1, w[x] = 0;
for(auto j : G[x]){
if(j == fa) continue;
get_root(j, x);
sz[x] += sz[j];
w[x] = max(w[x], sz[j]);
}
w[x] = max(w[x], n - sz[x]);
if(rt1 == 0 || w[x] < w[rt1]) rt1 = x, rt2 = 0;
else if(w[x] == w[rt1]) rt2 = x;
}
void dfs(int x, int fa){ // dfs计算hash值
f[x] = 1, sz[x] = 1;
for(auto j : G[x]){
if(j == fa) continue;
dfs(j, x);
f[x] += f[j] * p[sz[j]]; // 计算当前点hash
sz[x] += sz[j];
}
}
void init(int n){ // 初始化
rt1 = rt2 = 0;
for(int i = 1; i <= n; i++) G[i].clear();
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
random_shuffle(p + 1, p + 50); // 随机打乱
cin>>m;
for(int i = 1; i <= m; i++){
cin>>n;
init(n);
for(int j = 1; j <= n; j++){
int x; cin>>x;
if(x) G[x].push_back(j), G[j].push_back(x);
}
get_root(1, -1);
if(rt1){
dfs(rt1, -1);
Hash[i].push_back(f[rt1]);
}
if(rt2){
dfs(rt2, -1);
Hash[i].push_back(f[rt2]);
}
if(Hash[i].size() == 1) Hash[i].push_back(0);
if(Hash[i][0] < Hash[i][1]) swap(Hash[i][0], Hash[i][1]);
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= i; j++)
if(Hash[i][0] == Hash[j][0] && Hash[i][1] == Hash[j][1]){
cout<<j<<endl;
break;
}
return 0;
}
不知道为啥,邻接表存图就mle