zoukankan      html  css  js  c++  java
  • Subway (树中心 + 树hash)

    首先找到树的中心或者中心,我这里是找中心,因为我们需要找一个相同的起点,然后最多2个中心就是树的宽度为偶数时,奇数时为1个。

    找到之后需要对树进行hash,使得每个点都具备独特性,使之树的形态能够保证唯一,然后利用hash值,对树的每个节点下的节点进行排序,之后如果判定这两个树是一样的话,我只需要对树进行一次深搜并把遍历的顺序存进数组。然后直接按照数组中的值输出原来映射的字符串就好了。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    const int mod = 1e9 + 7;
    const int maxn = 1e5 + 12345;
    const int seed = 17;
    char inp[16], onp[16];
    
    struct Tree{
        map<string, int>id;
        vector<int>edge[maxn];
        string anw[maxn], rip[maxn];
        int _cnt, ctr[2], siz[maxn], dep[maxn], fa[maxn];
        LL Har[maxn];
        
        ///将遍历顺序存进去
        void done(int st, int fa){
            if(fa == 0) _cnt = 0;
            anw[_cnt ++] = rip[st];
            for(auto x : edge[st]){
                if(x == fa) continue;
                done(x, st);
            }
        }
    
        ///hash技术
        LL dfsh(int st, int fa){
            Har[st] = seed;siz[st] = 1;
            for(auto x : edge[st]){
                if(x == fa) continue;
                dfsh(x, st);
                siz[st] += siz[x];
            }
            sort(edge[st].begin(), edge[st].end(),
                [&](int x, int y){return Har[x] < Har[y];});
            for(auto x : edge[st]){
                if(x == fa) continue;
                Har[st] = (((Har[st] * Har[x]) % mod) ^ Har[x])% mod;
            }
            Har[st] = (Har[st] + siz[st]) % mod;
            Har[st] = (Har[st] * Har[st]) % mod;
            return Har[st];
        }
    
        ///得到深度值
        void getdep(int st, int Fa, int Dep){
            dep[st] = Dep;fa[st] = Fa;
            for(auto x : edge[st]){
                if(x == fa[st]) continue;
                getdep(x,st,Dep + 1);
            }
        }
    
        ///获取中点
        void getCtr(int n){
            getdep(1, 0, 0);
            ctr[0] = max_element(dep + 1, dep + 1 + n) - dep;
            getdep(ctr[0], 0, 0);
            ctr[0] = max_element(dep + 1, dep + 1 + n) - dep;
            int fdep = dep[ctr[0]];
            for(int i = 0; i < fdep/2; i ++)
                ctr[0] = fa[ctr[0]];
            ctr[1] = ctr[0];
            if(fdep & 1) ctr[1] = fa[ctr[1]];
        }
    
        ///重置数据
        void init(int n){
            for(int i = 0; i <= n; i ++)
                edge[i].clear();
            id.clear();_cnt = 1;
        }
    
        ///映射连接的符号,并存进对应的map值为下标的地方
        int toid(string v){
            if(id.find(v) != id.end()) return id[v];
            rip[_cnt] = v;
            return id[v] = _cnt ++;
        }
    
        ///建图,映射值
        void input(int n){
            init(n);int l,r;
            for(int i = 1; i < n; i ++){
                scanf("%s %s", inp, onp);
                l = toid(inp); r = toid(onp);
                edge[l].push_back(r);
                edge[r].push_back(l);
            }
        }
    }X, Y;
    
    void solve(){
        for(int i = 0; i < 2; i ++)
        for(int j = 0; j < 2; j ++)
        if(X.dfsh(X.ctr[i], 0) == Y.dfsh(Y.ctr[j], 0)){
            X.done(X.ctr[i], 0);
            Y.done(Y.ctr[j], 0);
            return;
        }
    }
    
    int main(){
        int n;while(~scanf("%d", &n)){
            X.input(n);
            Y.input(n);
            X.getCtr(n);
            Y.getCtr(n);
            solve();
            for(int i = 0; i < n; i ++)
                printf("%s %s
    ",X.anw[i].c_str(), Y.anw[i].c_str());
        }return 0;
    }

    这次的代码可以说是照搬过来的,菜鸡的自己。

    more crazy more get!
  • 相关阅读:
    【C++ 系列笔记】03 C++ 面向对象进阶
    【C++ 系列笔记】02 C++ 面向对象基础
    【C++ 系列笔记】01 C++ 与 C
    【JavaScript】简单取随机数 ~~(Math.random() * number)
    英语测试
    Linux指令入门
    RE-攻防世界 T3 insanity
    PWN-攻防世界 level0
    ISCC不会的理论题
    kali linux配置ssh
  • 原文地址:https://www.cnblogs.com/wethura/p/9739059.html
Copyright © 2011-2022 走看看