On this page
article
Isomorfismo de arvores
Sobre
thash() retorna o hash da arvore (usando centroids como vertices especiais).
Duas arvores sao isomorfas sse seu hash eh o mesmo
O(|V|.log(|V|))
Link original: treeIsomorf.cpp
Código
map<vector<int>, int> mphash;
struct tree {
int n;
vector<vector<int>> g;
vector<int> sz, cs;
tree(int n_) : n(n_), g(n_), sz(n_) {}
void dfs_centroid(int v, int p) {
sz[v] = 1;
bool cent = true;
for (int u : g[v]) if (u != p) {
dfs_centroid(u, v), sz[v] += sz[u];
if(sz[u] > n/2) cent = false;
}
if (cent and n - sz[v] <= n/2) cs.push_back(v);
}
int fhash(int v, int p) {
vector<int> h;
for (int u : g[v]) if (u != p) h.push_back(fhash(u, v));
sort(h.begin(), h.end());
if (!mphash.count(h)) mphash[h] = mphash.size();
return mphash[h];
}
ll thash() {
cs.clear();
dfs_centroid(0, -1);
if (cs.size() == 1) return fhash(cs[0], -1);
ll h1 = fhash(cs[0], cs[1]), h2 = fhash(cs[1], cs[0]);
return (min(h1, h2) << 30) + max(h1, h2);
}
};
// Versao mais rapida com hash, ideal para hash de floresta.
// subtree_hash(v, p) retorna o hash da subarvore enraizada em v com pai p.
// tree_hash() retorna o hash da arvore.
// forest_hash() retorna o hash da floresta.
// use o vetor forb[] para marcar vertices que nao podem ser visitados.
//
// O(|V|.log(|V|))
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int uniform(ll l, ll r) {
uniform_int_distribution<ll> uid(l, r);
return uid(rng);
}
const int MOD = 1e9 + 7;
const int H = 13;
const int P = uniform(1, MOD-1);
const int P2 = uniform(1, MOD-1);
struct tree {
int fn;
vector<vector<int>> g;
vector<int> sz, cs;
vector<bool> forb;
tree(int n_) : fn(n_), g(n_), sz(n_), forb(n_) {}
void dfs_size(int v, int p) {
sz[v] = 1;
for (int u : g[v]) if (u != p and !forb[u]) {
dfs_size(u, v), sz[v] += sz[u];
}
}
void dfs_centroid(int v, int p, int n) {
bool cent = true;
for (int u : g[v]) if (u != p and !forb[u]) {
dfs_centroid(u, v, n);
if(sz[u] > n/2) cent = false;
}
if (cent and n - sz[v] <= n/2) cs.push_back(v);
}
int subtree_hash(int v, int p) {
int h = H;
for (int u : g[v]) if (u != p and !forb[u]) {
h = ll(h) * (P + subtree_hash(u, v)) % MOD;
}
return h;
}
int tree_hash(int v=0) {
cs.clear();
dfs_size(v, -1);
dfs_centroid(v, -1, sz[v]);
if (cs.size() == 1) return subtree_hash(cs[0], -1);
assert (cs.size() == 2);
int h1 = subtree_hash(cs[0], cs[1]);
int h2 = subtree_hash(cs[1], cs[0]);
return ll(P + h1) * (P + h2) % MOD;
}
int forest_hash() {
fill(sz.begin(), sz.end(), 0);
int hash = 1;
for (int v = 0; v < fn; v++) if (!sz[v] and !forb[v]) {
hash = hash * ll(P2 + tree_hash(v)) % MOD;
}
return hash;
}
};