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 } 
View Code

 

posted @ 2017-06-09 15:36  lzw4896s  阅读(296)  评论(0编辑  收藏  举报