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

P5043 【模板】树同构([BJOI2015]树的同构) 树的hash题意对于两个树T1T_1T1​和T2T_2T2​,如果能够把树T1T_1T1​的所有点重新标号,使得树T1T_1T1​和树完T2T_2T2​全相同,那么这两个树是同构的。给你多棵树,输出与当前树同构的最小下标。分析对树搜重心,使用f[u]=∑v∈son(u)f[v]+p[sz[v]]f[u]=\sum_{v\inson(u)}f[v]+p[sz[v]]f[u]=∑v∈son(u)​f[v]+p[sz[v]]计算当前树的hashhashhash值ppp是质数数组,在最开始r

题意

对于两个树 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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/35383.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注