• 题解 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;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    在Android studio中,测试输出数组中最大子数组的和
    我所理解的软件开发模式
    java实现随机输出300题四则运算
    Demo(3月28日)
    关于构建之法中小飞问题的个人看法
    对搭档代码的一些意见
    项目复审
    安卓UI测试(基于android studio环境 espresso框架)
    读构建之法后的一些个人感受
    思考题
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/14175062.html
Copyright © 2020-2023  润新知