題解 P5043 【【模板】樹同構([BJOI2015]樹的同構)】
阿新 • • 發佈:2020-12-22
聽說題解裡全是 \(O(n^2m)\) 的,今天神 @hehezhou 介紹了一種優秀的方法。
用多項式雜湊,記錄走過的結點的順序。
首先如果是有根樹,而且兒子結點有先後遍歷順序這樣子就是對的。
然後如果兒子結點沒有順序就按照兒子的雜湊值排序,然後再雜湊。
有根樹拓展到無根樹只要找到重心然後再做即可。(兩個重心也是可以的,比較的時候看看兩個雜湊值能否對應上即可)
於是得出了雜湊值,最後暴力比較即可。
時間複雜度 \(\Theta(mn \log n)\), 時間複雜度瓶頸再於對雜湊值排序。
神仙 Forever_Pursuit
說他用基數排序,因此是 \(\Theta(mn)\)。
程式碼:
#include<bits/stdc++.h> #define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++) #define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--) #define ll long long #define ull unsigned long long #define db double #define pii pair<int, int> #define pil pair<int, lonf long> #define mkp make_pair using namespace std; const int N = 55; const int mod = 1019260817; const int G = 19491001; int Pow[N]; int n, m; struct Tree { int A, B; } f[N]; bool operator == (Tree aa, Tree bb) { return aa.A == bb.A && aa.B == bb.B; } int head[N], edge_id; struct edge { int to, next; } e[N << 1]; void add_edge(int u, int v) { ++edge_id, e[edge_id].to = v, e[edge_id].next = head[u], head[u] = edge_id; } int has[N], siz[N], dep[N], rt, rrt, rtm; void findrt(int x, int fa) { siz[x] = 1; int maxn = 0; for(int i = head[x]; i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; findrt(v, x), siz[x] += siz[v], maxn = max(maxn, siz[v]); } maxn = max(maxn, n - siz[x]); if(maxn < rtm) rtm = maxn, rt = x, rrt = 0; else if(maxn == rtm) rrt = x; } int tot; pii sav[N]; void dfs(int x, int fa) { has[x] = 1ll * dep[x] * Pow[1] % mod, siz[x] = 1; for(int i = head[x]; i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; dep[v] = dep[x] + 1, dfs(v, x); } tot = 0; for(int i = head[x]; i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; sav[++tot] = mkp(has[v], siz[v]); } sort(sav + 1, sav + tot + 1); L(i, 1, tot) (has[x] += 1ll * sav[i].first * Pow[siz[x]] % mod) %= mod, siz[x] += sav[i].second; } void In(int x) { rtm = mod, rrt = 0; scanf("%d", &n); L(i, 1, n) { int v; scanf("%d", &v); if(v) add_edge(i, v), add_edge(v, i); } findrt(1, -1); dep[rt] = 1, dfs(rt, -1), f[x].A = has[rt]; if(rrt) dep[rrt] = 1, dfs(rrt, -1), f[x].B = has[rrt]; if(f[x].A < f[x].B) swap(f[x].A, f[x].B); L(i, 1, n) head[i] = 0; edge_id = 0; } int mian() { Pow[0] = 1; L(i, 1, 50) Pow[i] = 1ll * Pow[i - 1] * G % mod; scanf("%d", &m); L(i, 1, m) In(i); L(i, 1, m) L(j, 1, i) if(f[i] == f[j]) { printf("%d\n", j); break; } return 0; }
祝大家學習愉快!