uva12489 Combating cancer(树同构)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3933
给你两棵无根树,让你判断这两棵树是否同构
不会判断树同构,果断抄了个模板,乱搞给过掉了。
首先由于给的是无根树,而要判断无根树是否同构得以重心为根,然后做一个括号序列的哈希。
于是我们需要先找出重心,要找树的重心得先知道直径。
找出直径,直径上的点的个数是偶数,那么重心是中间的两个点,如果是奇数个,那么重心是中间那个。
或者说是根据拓排,每次度数为1的点入队,留下的最后一批就是。
然而我当时脑抽了一下,求好直径,后用第二种再去搞。。。其实求直径的时候保存一下路径就好了。
最后,如果有两个重心就做两次哈希,得到两个哈希值,一个就一次。
最后把两棵树的哈希值比一下是否有相同的。
/** * code generated by JHelper * More info: https://github.com/AlexeyDmitriev/JHelper * @author xyiyy @https://github.com/xyiyy */ #include <iostream> #include <fstream> //##################### //Author:fraud //Blog: http://www.cnblogs.com/fraud/ //##################### //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define pb(X) push_back(X) #define rep(X, N) for(int X=0;X<N;X++) #define ALL(X) (X).begin(),(X).end() typedef unsigned long long ull; const int maxNode = 10010; const int maxEdge = (maxNode << 1); // // Created by xyiyy on 2015/8/14. // #ifndef ICPC_HASHTREE_HPP #define ICPC_HASHTREE_HPP //树的同构,返回哈希值 //输入有根树的根,或者无根树的重心 typedef unsigned long long ull; const ull MAGIC = 321; // // Created by xyfra_000 on 2015/8/14. // #ifndef ICPC_ADJLIST_ARRAY_HPP #define ICPC_ADJLIST_ARRAY_HPP #define Foredge(A, X) for(int A = From[X];A!=-1;A = Next[A]) int From[maxEdge], To[maxEdge]; int Next[maxEdge]; int Edgecnt; void init(int n) { rep(i, n + 1)From[i] = -1; Edgecnt = 0; } void addedge(int u, int v) { To[Edgecnt] = v; Next[Edgecnt] = From[u]; From[u] = Edgecnt++; } #endif //ICPC_ADJLIST_ARRAY_HPP ull powMod(ull a, int n) { ull ret = 1ULL; while (n) { if (n & 1)ret *= a; a *= a; n >>= 1; } return ret; } struct Hash { int length; ull value; Hash() : length(0), value(0) { } Hash(char c) : length(1), value(c) { } Hash(int l, int v) : length(l), value(v) { } }; bool operator<(const Hash &a, const Hash &b) { return a.value < b.value; } Hash operator+(const Hash &a, const Hash &b) { return Hash(a.length + b.length, a.value * powMod(MAGIC, b.length) + b.value); } void operator+=(Hash &a, Hash &b) { a = a + b; } vector<Hash> childs[maxNode]; Hash dfs(int pre, int cur) { Hash ret; childs[cur].clear(); for (int iter = From[cur]; iter != -1; iter = Next[iter]) { if (To[iter] != pre) { childs[cur].pb(dfs(cur, To[iter])); } } sort(ALL(childs[cur])); for (vector<Hash>::iterator iter = childs[cur].begin(); iter != childs[cur].end(); iter++) { ret += *iter; } Hash retL = Hash('('); ret = '(' + ret + ')'; return ret; } ull getHash(int root) { return dfs(-1, root).value; } #endif //ICPC_HASHTREE_HPP // // Created by xyfra_000 on 2015/8/14. // #ifndef ICPC_TREEDIAMETER_HPP #define ICPC_TREEDIAMETER_HPP //求树的直径 //可以通过修改dfs部分变成求带权的树的直径 vector<int> dist; void dfs(int p, int u, int d) { dist[u] = d; Foredge(i, u) { if (To[i] != p) { dfs(u, To[i], d + 1); } } } int getDiameter(int n) { dist.resize(n); dfs(-1, 0, 0); int u = max_element(ALL(dist)) - dist.begin(); dfs(-1, u, 0); return *max_element(ALL(dist)); } #endif //ICPC_TREEDIAMETER_HPP int deg[maxNode]; int vis[maxNode]; class TaskH { public: void solve(std::istream &in, std::ostream &out) { int n; while (in >> n) { vector<ull> ans[2]; rep(times, 2) { int u, v; init(n); rep(i, n + 1)deg[i] = 0; rep(i, n + 1)vis[i] = 0; queue<int> q; rep(i, n - 1) { in >> u >> v; u--, v--; deg[u]++; deg[v]++; addedge(u, v); addedge(v, u); } int dia = getDiameter(n); int num = n; rep(i, n) { if (deg[i] == 1) { q.push(i); } } int gao = 1; if (dia & 1)gao++; while (num > gao && !q.empty()) { u = q.front(); q.pop(); vis[u] = 1; num--; deg[u]--; for (int i = From[u]; i != -1; i = Next[i]) { int v = To[i]; if (!vis[v]) { deg[v]--; if (deg[v] == 1) { q.push(v); } } } } rep(i, n) { if (!vis[i]) { ans[times].pb(getHash(i)); } } } bool ok = 0; rep(i, ans[0].size()) { rep(j, ans[1].size()) { if (ans[0][i] == ans[1][j])ok = 1; } } if (ok)out << "S" << endl; else out << "N" << endl; } } }; int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); TaskH solver; std::istream &in(std::cin); std::ostream &out(std::cout); solver.solve(in, out); return 0; }