HDU5732 Subway树重心 树哈希

Posted kikokiko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU5732 Subway树重心 树哈希相关的知识,希望对你有一定的参考价值。

HDU5732 Subway

题意:

给出两棵大小为(N)的同构树,要求输出对应的节点
(Nle 10^5)

题解:

由于重心最多只有两个,找到重心之后以重心为根进行树哈希,找到相同哈希值的根之后递归输出即可
输出儿子的时候要先对哈希值排序,保证递归进去的儿子节点也是同构的
这里用的哈希方法是(f[u] = 1 + sum_{vin son_u}f[v]cdot prime[sz[v]])

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef uint64_t ull;
const int MAXN = 2e5+7;
vector<int> prime;
void sieve(){
    vector<bool> pm(MAXN,true);
    for(int i = 2; i < MAXN; i++){
        if(pm[i]) prime.push_back(i);
        for(int j = 0; j < (int)prime.size(); j++){
            if(i*prime[j]>=MAXN) break;
            pm[i*prime[j]] = false;
            if(i%prime[j]==0) break;
        }
    }
}
int n;
struct Tree{
    vector<int> G[MAXN];
    map<string,int> msk;
    string name[MAXN];
    int sz[MAXN],maxsz[MAXN];
    ull hashval[MAXN];
    int tot,root;
    void clear(){
        for(int i = 1; i <= tot; i++) G[i].clear();
        tot = 0;
        msk.clear();
    }
    int getID(string &s){
        if(!msk.count(s)){
            msk[s] = ++tot;
            name[tot] = s;
        }
        return msk[s];
    }
    void dfs(int u, int f){
        sz[u] = 1; maxsz[u] = 0;
        for(int v : G[u]){
            if(v==f) continue;
            dfs(v,u);
            sz[u] += sz[v];
            maxsz[u] = max(maxsz[u],sz[v]);
        }
        maxsz[u] = max(maxsz[u],tot-sz[u]);
    }
    void getHash(int u, int f){
        sz[u] = 1;
        hashval[u] = 1ull;
        for(int v : G[u]){
            if(v==f) continue;
            getHash(v,u);
            sz[u] += sz[v];
            hashval[u] += hashval[v] * prime[sz[v]];
        }
    }
}tr[2];
void match(int u0, int u1, int f0, int f1){
    cout << tr[0].name[u0] << ‘ ‘ << tr[1].name[u1] << endl;
    tr[0].hashval[f0] = UINT64_MAX;
    tr[1].hashval[f1] = UINT64_MAX;
    sort(tr[0].G[u0].begin(),tr[0].G[u0].end(),[&](const int &x, const int &y){
        return tr[0].hashval[x] < tr[0].hashval[y];
    });
    sort(tr[1].G[u1].begin(),tr[1].G[u1].end(),[&](const int &x, const int &y){
        return tr[1].hashval[x] < tr[1].hashval[y];
    });
    int m = (int)tr[0].G[u0].size() - (f0==0?0:1);
    for(int i = 0; i < m; i++)
        match(tr[0].G[u0][i],tr[1].G[u1][i],u0,u1);
}
void solve(){
    tr[0].clear(); tr[1].clear();
    for(int t = 0; t < 2; t++){
        for(int i = 1; i < n; i++){
            string s1, s2;
            cin >> s1 >> s2;
            int u = tr[t].getID(s1);
            int v = tr[t].getID(s2);
            tr[t].G[u].push_back(v);
            tr[t].G[v].push_back(u);
        }
    }
    tr[0].dfs(1,0);
    int hsz = *min_element(tr[0].maxsz+1,tr[0].maxsz+1+n);
    for(int i = 1; i <= n; i++){
        if(tr[0].maxsz[i]==hsz){
            tr[0].root = i;
            break;
        }
    }
    tr[0].getHash(tr[0].root,0);
    ull hax = tr[0].hashval[tr[0].root];
    tr[1].dfs(1,0);
    for(int i = 1; i <= n; i++){
        if(tr[1].maxsz[i]==hsz){
            tr[1].getHash(i,0);
            if(hax==tr[1].hashval[i]){
                tr[1].root = i;
                break;
            }
        }
    }
    match(tr[0].root,tr[1].root,0,0);
}

int main(){
    ____();
    sieve();
    while(cin >> n) solve();
    return 0;
}



以上是关于HDU5732 Subway树重心 树哈希的主要内容,如果未能解决你的问题,请参考以下文章

POJ1635 Subway tree systems ——(判断树的同构,树的最小表示法)

树哈希 学习笔记

树同构/树哈希

哈希算法在判定树同构方面的应用(下)

Subway (树中心 + 树hash)

HDU6567树的重心换根DP