题解 P5043 【【模板】树同构([BJOI2015]树的同构)】

听说题解里全是 (O(n^2m)) 的,今天神 @hehezhou 介绍了一种优秀的方法。

用多项式哈希,记录走过的结点的顺序。

首先如果是有根树,而且儿子结点有先后遍历顺序这样子就是对的。

然后如果儿子结点没有顺序就按照儿子的哈希值排序,然后再哈希。

有根树拓展到无根树只要找到重心然后再做即可。(两个重心也是可以的,比较的时候看看两个哈希值能否对应上即可)

于是得出了哈希值,最后暴力比较即可。

时间复杂度 (Theta(mn log n)), 时间复杂度瓶颈再于对哈希值排序。

神仙 Forever_Pursuit说他用基数排序,因此是 (Theta(mn))

代码:

#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++) 
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
#define ll long long
#define ull unsigned long long 
#define db double
#define pii pair<int, int>
#define pil pair<int, lonf long>
#define mkp make_pair
using namespace std;
const int N = 55;
const int mod = 1019260817;
const int G = 19491001;
int Pow[N];
int n, m;
struct Tree {
	int A, B;
} f[N];
bool operator == (Tree aa, Tree bb) {
	return aa.A == bb.A && aa.B == bb.B;
}
int head[N], edge_id;
struct edge {
	int to, next;
} e[N << 1];
void add_edge(int u, int v) {
	++edge_id, e[edge_id].to = v, e[edge_id].next = head[u], head[u] = edge_id;
}
int has[N], siz[N], dep[N], rt, rrt, rtm;
void findrt(int x, int fa) {
	siz[x] = 1;
	int maxn = 0;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].to;
		if(v == fa) continue;
		findrt(v, x), siz[x] += siz[v], maxn = max(maxn, siz[v]);
	}
	maxn = max(maxn, n - siz[x]);
	if(maxn < rtm) rtm = maxn, rt = x, rrt = 0;
	else if(maxn == rtm) rrt = x;
}
int tot;
pii sav[N];
void dfs(int x, int fa) {
	has[x] = 1ll * dep[x] * Pow[1] % mod, siz[x] = 1;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].to;
		if(v == fa) continue;
		dep[v] = dep[x] + 1, dfs(v, x);
	}
	tot = 0;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].to;
		if(v == fa) continue;
		sav[++tot] = mkp(has[v], siz[v]);
	}
	sort(sav + 1, sav + tot + 1);
	L(i, 1, tot) (has[x] += 1ll * sav[i].first * Pow[siz[x]] % mod) %= mod, siz[x] += sav[i].second;
}
void In(int x) {
	rtm = mod, rrt = 0;
	scanf("%d", &n);
	L(i, 1, n) {
		int v; scanf("%d", &v);
		if(v) add_edge(i, v), add_edge(v, i);
	}
	findrt(1, -1);
	dep[rt] = 1, dfs(rt, -1), f[x].A = has[rt];
	if(rrt) dep[rrt] = 1, dfs(rrt, -1), f[x].B = has[rrt];
	if(f[x].A < f[x].B) swap(f[x].A, f[x].B);
	L(i, 1, n) head[i] = 0;
	edge_id = 0;
}
int mian() {
	Pow[0] = 1;
	L(i, 1, 50) Pow[i] = 1ll * Pow[i - 1] * G % mod;
	scanf("%d", &m);
	L(i, 1, m) In(i);
	L(i, 1, m) L(j, 1, i) if(f[i] == f[j]) {
		printf("%d
", j);
		break;
	}
	return 0;
}

祝大家学习愉快!

原文地址:https://www.cnblogs.com/zkyJuruo/p/14175062.html