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

题意

对于两个树 T 1 T_1 T1 T 2 T_2 T2,如果能够把树 T 1 T_1 T1 的所有点重新标号,使得树 T 1 T_1 T1 和树 完 T 2 T_2 T2 全相同,那么这两个树是同构的。给你多棵树,输出与当前树同构的最小下标。

分析

对树搜重心,使用 f [ u ] = ∑ v ∈ s o n ( u ) f [ v ] + p [ s z [ v ] ] f[u]=\sum_{v\in son(u)}f[v]+p[sz[v]] f[u]=vson(u)f[v]+p[sz[v]] 计算当前树的 h a s h hash hash
p p p是质数数组,在最开始 r a n d o m _ s h u f f l e random\_shuffle random_shuffle进行随机排序。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = N * 2, inf = 1e8;
int p[70] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281};
int m, n;
int sz[N], w[N], rt1, rt2;
ull f[N];
vector<int> G[N];
vector<ull> Hash[N];
void get_root(int x, int fa){ // 搜重心
    sz[x] = 1, w[x] = 0;
    for(auto j : G[x]){
        if(j == fa) continue;
        get_root(j, x);
        sz[x] += sz[j];
        w[x] = max(w[x], sz[j]);
    }
    w[x] = max(w[x], n - sz[x]);
    if(rt1 == 0 || w[x] < w[rt1]) rt1 = x, rt2 = 0;
    else if(w[x] == w[rt1]) rt2 = x;
}
void dfs(int x, int fa){ // dfs计算hash值
    f[x] = 1, sz[x] = 1;
    for(auto j : G[x]){
        if(j == fa) continue;
        dfs(j, x);
        f[x] += f[j] * p[sz[j]]; // 计算当前点hash
        sz[x] += sz[j];
    }
}
void init(int n){ // 初始化
    rt1 = rt2 = 0;
    for(int i = 1; i <= n; i++) G[i].clear();
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    random_shuffle(p + 1, p + 50); // 随机打乱
    cin>>m;
    for(int i = 1; i <= m; i++){
        cin>>n;
        init(n);
        for(int j = 1; j <= n; j++){
            int x; cin>>x;
            if(x) G[x].push_back(j), G[j].push_back(x);
        }
        get_root(1, -1); 
        if(rt1){
            dfs(rt1, -1);
            Hash[i].push_back(f[rt1]);
        }
        if(rt2){
            dfs(rt2, -1);
            Hash[i].push_back(f[rt2]);
        }
        if(Hash[i].size() == 1) Hash[i].push_back(0);
        if(Hash[i][0] < Hash[i][1]) swap(Hash[i][0], Hash[i][1]);
    }
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= i; j++)
            if(Hash[i][0] == Hash[j][0] && Hash[i][1] == Hash[j][1]){
                cout<<j<<endl;
                break;
            }
    return 0;
}

不知道为啥,邻接表存图就mle

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值