作者:XiaoQuQu,发表于 Tue Jul 09 2024。
如果要判两个有根树同构,可以使用树哈希。一个树哈希是 $f_x=(\sum g(f_u))+c\bmod m$,其中 $g$ 是一个从整数到整数的映射,$c$ 是一个常数,$m$ 是模数,可以使用自然溢出。
在这里 $g$ 使用 xor-shift 算法,听 oi-wiki 说要在前后异或一个相同的 mask,不知道有什么用。
const int MAXN = 1e6 + 5;
using ull = unsigned long long;
int n;
ull msk, f[MAXN];
set<ull> st;
vector<int> G[MAXN];
ull nxt(ull x) {
x ^= msk;
x ^= x << 13;
x ^= x >> 5;
x ^= x << 17;
x ^= msk;
return x;
}
void dfs(int x, int fa) {
f[x] = 19260813;
for (auto u:G[x]) {
if (u == fa) continue;
dfs(u, x);
f[x] = f[x] + nxt(f[u]);
}
st.insert(f[x]);
}
void work() {
msk = rand();
cin >> n;
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
cout << st.size() << endl;
}
对于每个树,以这个树里的每个点为根,算一次树哈希,然后暴力判断即可,时间复杂度 $O(n^4)$。
const int MAXN = 55;
using ull = unsigned long long;
int m, n[MAXN];
ull f[MAXN][MAXN][MAXN], msk;
vector<int> G[MAXN][MAXN];
ull nxt(ull x) {
x ^= msk;
x ^= x << 13;
x ^= x >> 5;
x ^= x << 17;
x ^= msk;
return x;
}
void dfs(int x, int fa, int rt, int id) {
f[id][rt][x] = 19260813;
for (auto u:G[id][x]) {
if (u == fa) continue;
dfs(u, x, rt, id);
f[id][rt][x] += nxt(f[id][rt][u]);
}
}
void work() {
msk = rand();
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> n[i];
for (int j = 1; j <= n[i]; ++j) {
int f; cin >> f;
if (!f) continue;
G[i][j].push_back(f);
G[i][f].push_back(j);
}
}
for (int i = 1; i <= m; ++i) {
int ans = INT_MAX;
for (int j = 1; j <= n[i]; ++j) {
dfs(j, 0, j, i);
for (int k = 1; k <= i; ++k) {
if (n[i] != n[k]) continue;
for (int l = 1; l <= n[k]; ++l) {
if (f[i][j][j] == f[k][l][l]) ans = min(ans, k);
}
}
}
cout << ans << endl;
}
}
Copyright © 2024 LVJ, Open-Source Project. 本站内容在无特殊说明情况下均遵循 CC-BY-SA 4.0 协议,内容版权归属原作者。