TIOJ 1214 樹同構

TIOJ 1214 - 樹論 之 樹同構測試

ICPC 2020 Taipei 出了一題水母圖的同構,於是今天找了這題樹同構練習,採用括號字串的方法,而不是 Hashing。

  • 水母圖
    • 對於環上每個點當 root 去生出樹字串。
    • 串接起來後,用環狀字串的演算法去比較。

TIOJ 1214 - 樹論 之 樹同構測試

$$O(|G|^2 \log \Delta(G)) = O(n^2 \log n)$$

  • n ≤ 100。給定兩棵樹的邊,問他們是否同構 “isomorphic”
  • 先 DFS 找出所有的樹重心(最多 2 個)。樹重心的定義為,最大子樹大小最小的點。
  • 從重心開始做 DFS,將每個點用 () 表示,中間夾括入他所有子樹字串,將他們排序後加入。每次排序為度數個,所以總共需要排序 deg - 1 個,所有點加起來為 n 個,再乘上字串比較的複雜度 O(n)。
  • 最後再將重心們的字串排序後串接,比較兩棵樹是否相同。
 1#pragma GCC optimization ("O3")
 2#include<bits/stdc++.h>
 3using namespace std;
 4#define pb push_back
 5int n;
 6int dfs(int u, int p, int &mi, vector<vector<int> > &G, vector<int> &ret) {
 7    int cnt = 0, mx = 0;
 8    for (int uu : G[u]) {
 9        if (uu == p) continue;
10        int r = dfs(uu, u, mi, G, ret);
11        mx = max(mx, r), cnt += r;
12    }
13    mx = max(mx, n - cnt - 1);
14    if (mx <= mi) {
15        if (mx < mi) ret.clear(), mi = mx;
16        ret.pb(u);
17    }
18    return cnt + 1;
19}
20vector<int> centroid(vector<vector<int> > &G) {
21    vector<int> ret;
22    int mi = n;
23    dfs(1, -1, mi, G, ret);
24    return ret;
25}
26string tree(int u, int p, vector<vector<int> > &G) {
27    string ret = "";
28    vector<string> sub;
29    for (int uu : G[u])
30        if (uu != p) sub.pb(tree(uu, u, G));
31    sort(sub.begin(), sub.end());
32    for (string s : sub) ret += s;
33    return "(" + ret + ")";
34}
35string solve() {
36    vector<vector<int> > G(n + 1);
37    for (int i = 1; i < n; i++) {
38        int a, b; cin >> a >> b;
39        G[a].pb(b), G[b].pb(a);
40    }
41    vector<string> ans;
42    for (int u : centroid(G)) ans.pb(tree(u, -1, G));
43    sort(ans.begin(), ans.end());
44    string ret = "";
45    for (string s : ans) ret += s;
46    return ret;
47}
48int main() {
49    ios::sync_with_stdio(0), cin.tie(0);
50    while (1) {
51        cin >> n; if (!n) break;
52        cout << (solve() == solve() ? "Same" : "Different") << '\n';
53    }
54    return 0;
55}
Built with Hugo
Theme Stack designed by Jimmy