Hourrank 21 Tree Isomorphism 树hash
https://www.hackerrank.com/contests/hourrank-21/challenges/tree-isomorphism
题目大意:
给出一棵树, 求有多少本质不同的子树。 N <= 19
下面给出我综合了网上一些做法后设计的hash函数(我不会证明碰撞概率)
判断两棵有根树是否相同:
将子树的Hash值从小到大排序, Hash(x) = A * p xor Hash(son_1) mod q * p xor Hash(son_2) mod q .... * p xor Hash(son_k) mod q * B mod q
判断两棵无根树是否相同:
找到重心 u, v(u 可能等于v, 即只有一个重心) 分别以它们为根求有根树Hash。不妨设 Hash(u) <= Hash(v)
Unrooted_Hash(x) = triple(n, u, v) n为节点数。
对于本题, 只要暴力将每个子树的Unrooted_Hash 插入到set里就好了。
代码:
1 //https://www.hackerrank.com/contests/hourrank-21/challenges/tree-isomorphism 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <cmath> 6 #include <algorithm> 7 #include <vector> 8 #include <map> 9 #include <queue> 10 #include <set> 11 using namespace std; 12 13 typedef long long ll; 14 15 #define N 20 16 const int INF = 1 << 30; 17 const int P = 10007, A = 31, B = 7; 18 const ll mod = 1e12 + 22333; 19 const double pi = acos(-1); 20 21 22 vector<int> E[N], cone; 23 int size[N], cnt; 24 set<pair<int, pair<ll, ll> > > st; 25 26 int DFS_SIZE(int x, int pre) 27 { 28 int res = 1; 29 for (int i = 0; i < E[x].size(); ++i) 30 { 31 int y = E[x][i]; 32 if (y == pre) continue; 33 res += DFS_SIZE(y, x); 34 } 35 return size[x] = res; 36 } 37 38 void Find_Cone(int x, int pre) 39 { 40 bool f = true; 41 for (int i = 0; i < E[x].size(); ++i) 42 { 43 int y = E[x][i]; 44 if (y == pre) continue; 45 Find_Cone(y, x); 46 if (size[y] > cnt / 2) f = false; 47 } 48 if (cnt - size[x] > cnt / 2) f = false; 49 if (f) cone.push_back(x); 50 } 51 52 ll Hash(int x, int pre) 53 { 54 vector<ll> res; 55 for (int i = 0; i < E[x].size(); ++i) 56 { 57 int y = E[x][i]; 58 if (y == pre) continue; 59 res.push_back(Hash(y, x)); 60 } 61 sort(res.begin(), res.end()); 62 63 ll h = A; 64 for (int i = 0; i < res.size(); ++i) h = (h * P ^ res[i]) % mod; 65 h = h * B % mod; 66 return h; 67 } 68 69 int main() 70 { 71 //freopen("in.in", "r", stdin); 72 //freopen("out.out", "w", stdout); 73 74 int n, x, y, a[20], b[20]; 75 cin >> n; 76 for (int i = 0; i < n - 1; ++i) cin >> a[i] >> b[i], --a[i], --b[i]; 77 for (int mask = 1; mask < (1 << n); ++mask) 78 { 79 for (int i = 0; i < n; ++i) E[i].clear(); 80 cone.clear(); cnt = 0; 81 for (int i = 0; i < n - 1; ++i) 82 { 83 if ((mask & (1 << a[i])) && (mask & (1 << b[i]))) 84 { 85 E[a[i]].push_back(b[i]); 86 E[b[i]].push_back(a[i]); 87 } 88 } 89 int root; 90 for (int i = 0; i < n; ++i) if (mask & (1 << i)) root = i, ++cnt; 91 if (DFS_SIZE(root, -1) != cnt) continue; 92 93 Find_Cone(root, -1); 94 if (cone.size() == 1) 95 { 96 ll h = Hash(cone[0], -1); 97 st.insert(make_pair(cnt, make_pair(h, h))); 98 } 99 else 100 { 101 ll h1 = Hash(cone[0], -1), h2 = Hash(cone[1], -1); 102 if (h1 > h2) swap(h1, h2); 103 st.insert(make_pair(cnt, make_pair(h1, h2))); 104 } 105 } 106 printf("%d\n", (int)st.size()); 107 return 0; 108 }
Every day is meaningful, keeping learning!