无根树同构_hash
先贴上地址 https://vjudge.net/problem/HDU-5732
判断有根树同构:
1. 直接用括号最小表示法
2. 利用括号最小表示法的思想进行hash
判断无根树同构:
1. 找到树的重心.
2. 以重心为根, 把无根树转化成有根树. 按照有根树同构的方法判断是否同构.
同构的过程中,为什么可以sort.
我们知道,对于树来说,
树的节点绕着它的父节点旋转,树的结构就不会被改变的.
所以sort的过程就相当于把树的节点绕着它的父节点进行旋转.
// sort的话,可以这么理解:
我们是按照同样的规则(我们保证这个规则可以唯一确定一棵树,),
对两棵树进行操作,如果同构的话,那么结果应该是一样的. 如果不同构的画 那么结果就是不一样的
至于树的括号表达式, 可以见这几个博客
括号表达式 https://www.byvoid.com/zhs/blog/directed-tree-bracket-sequence
树同构 https://blog.csdn.net/u010152669/article/details/9116975
树的表示方法 https://www.cnblogs.com/jsawz/p/6807636.html
#include <cstdio> #include <ctime> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <vector> using namespace std; typedef unsigned long long ull; const int maxn = 1e5+10; ull x[maxn]; int ans[maxn]; struct Edge { int lst; int to; }; class Tree { public : Edge edge[maxn<<1]; int head[maxn]; int cn, csz, ccnt, mid[3]; int rcd[maxn]; ull cnode[maxn]; ull vvvvv[3]; map<string, int> id; char name[maxn][16]; inline void add(int u, int v) { edge[csz].lst = head[u]; edge[csz].to = v; head[u] = csz++; } int dfs(int u, int fa) { int i, v, res = 0, t1; for (i=head[u]; i; i=edge[i].lst) { v = edge[i].to; if (v == fa) continue; t1 = dfs(v, u); res += t1; if (rcd[u] < t1) rcd[u] = t1; if (rcd[v] < cn-t1) rcd[v] = cn-t1; } return res + 1; } ull dfs2(int u, int fa, int deep) { int i, v, res = 0, t1; vector<ull> son; for (i=head[u]; i; i=edge[i].lst) { v = edge[i].to; if (v == fa) continue; son.push_back(dfs2(v, u, deep+1)); } sort(son.begin(), son.end()); // 判断树同构 注意要sort后乘一个随机数(或者一个质数的i次方). 为什么可以sort呢? 因为树同一层的节点围绕父节点旋转不会改变树的结构. 而sort相当于把节点绕父节点旋转了. for (i=0, t1=son.size(); i<t1; ++i) res += son[i] * x[i+1]; return cnode[u] = (res ? res : x[deep]); } void init(int n) { cn = n; csz = 1; id.clear(); int i, u, v, cnt = 1; char s1[16], s2[16]; for (i=1; i<=n; ++i) rcd[i] = head[i] = 0; for (i=1; i<n; ++i) { scanf("%s%s", s1, s2); if (!(u = id[s1])) { strcpy(name[cnt], s1); id[s1] = u = cnt++; } if (!(v = id[s2])) { strcpy(name[cnt], s2); id[s2] = v = cnt++; } add(u, v); add(v, u); } dfs(1, -1); int mm = 0x3f3f3f3f; for (i=1; i<=n; ++i) { if (mm > rcd[i]) { mm = rcd[i]; ccnt = 0; mid[++ccnt] = i; } else if (mm == rcd[i]) mid[++ccnt] = i; } for (i=1; i<=ccnt; ++i) vvvvv[i] = dfs2(mid[i], -1, 1); } }te1, te2; struct nobe { int id; ull val; bool operator < (const nobe &a) const { return val < a.val; } nobe () {} nobe (int iid, ull vval) : id(iid), val(vval) {} }; void dfs3(int u1, int u2, int fa1, int fa2) { int i, v1, v2, tsz; ans[u1] = u2; vector<nobe> ve1, ve2; for (i=te1.head[u1]; i; i=te1.edge[i].lst) { v1 = te1.edge[i].to; if (v1 == fa1) continue; ve1.push_back(nobe(v1, te1.cnode[v1])); } for (i=te2.head[u2]; i; i=te2.edge[i].lst) { v2 = te2.edge[i].to; if (v2 == fa2) continue; ve2.push_back(nobe(v2, te2.cnode[v2])); } sort(ve1.begin(), ve1.end()); sort(ve2.begin(), ve2.end()); for (i=0, tsz=ve1.size(); i<tsz; ++i) dfs3(ve1[i].id, ve2[i].id, u1, u2); } int main() { int i, j, k, n; srand(time(NULL)); for (i=0; i<maxn; ++i) x[i] = rand(); while (~scanf("%d", &n)) { te1.init(n); te2.init(n); for (i=1; i<=te1.ccnt; ++i) for (j=1; j<=te2.ccnt; ++j) { if (te1.vvvvv[i] == te2.vvvvv[j]) { dfs3(te1.mid[i], te2.mid[j], te1.mid[i], te2.mid[j]); for (k=1; k<=n; ++k) printf("%s %s\n", te1.name[k], te2.name[ans[k]]); goto A; } } A: ; } return 0; }