无根树同构_hash

无根树同构_hash先贴上地址https://vjudge.net/problem/HDU-5732判断有根树同构:1.直接用括号最小表示法2.利用括号最小表示法的思想进行hash判断无根树同构:1.找到树的重心.2.以重心为根,把无根树转化成有根树.按照有根树同构的方法判断是否同构.同构的过程中,为什么可以sort….

先贴上地址 https://vjudge.net/problem/HDU-5732

 

判断有根树同构: 

     1. 直接用括号最小表示法

     2. 利用括号最小表示法的思想进行hash

判断无根树同构:

     1. 找到树的重心.

     2. 以重心为根, 把无根树转化成有根树. 按照有根树同构的方法判断是否同构.

 

同构的过程中,为什么可以sort.

我们知道,对于树来说,

树的节点绕着它的父节点旋转,树的结构就不会被改变的.

所以sort的过程就相当于把树的节点绕着它的父节点进行旋转.  

 // sort的话,可以这么理解:

  我们是按照同样的规则(我们保证这个规则可以唯一确定一棵树,),

  对两棵树进行操作,如果同构的话,那么结果应该是一样的. 如果不同构的画 那么结果就是不一样的

至于树的括号表达式, 可以见这几个博客  

  括号表达式       https://www.byvoid.com/zhs/blog/directed-tree-bracket-sequence

  树同构              https://blog.csdn.net/u010152669/article/details/9116975

  树的表示方法   https://www.cnblogs.com/jsawz/p/6807636.html

 

#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>

using namespace std;

typedef unsigned long long ull;
const int maxn = 1e5+10;
ull x[maxn];
int ans[maxn];

struct Edge {
    int lst;
    int to;
};

class Tree {
public :
    Edge edge[maxn<<1];
    int head[maxn];
    int cn, csz, ccnt, mid[3];
    int rcd[maxn];
    ull cnode[maxn];
    ull vvvvv[3];
    map<string, int> id;
    char name[maxn][16];
    
    inline void add(int u, int v) {
        edge[csz].lst = head[u];
        edge[csz].to  = v;
        head[u] = csz++;
    }
    
    int dfs(int u, int fa) {
        int i, v, res = 0, t1;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (v == fa) continue;
            t1 = dfs(v, u);
            res += t1;
            if (rcd[u] < t1) rcd[u] = t1;
            if (rcd[v] < cn-t1) rcd[v] = cn-t1; 
        }
        return res + 1;
    }
    
    ull dfs2(int u, int fa, int deep) {
        int i, v, res = 0, t1;
        vector<ull> son;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (v == fa) continue; 
            son.push_back(dfs2(v, u, deep+1));
        }
        sort(son.begin(), son.end()); // 判断树同构 注意要sort后乘一个随机数(或者一个质数的i次方).  为什么可以sort呢? 因为树同一层的节点围绕父节点旋转不会改变树的结构. 而sort相当于把节点绕父节点旋转了. 
        for (i=0, t1=son.size(); i<t1; ++i) 
            res += son[i] * x[i+1];
        return cnode[u] = (res ? res : x[deep]);
    }
    
    void init(int n) {
        cn = n; csz = 1; id.clear();
        int i, u, v, cnt = 1;
        char s1[16], s2[16];
        
        for (i=1; i<=n; ++i) rcd[i] = head[i] = 0;
        
        for (i=1; i<n; ++i) {
            scanf("%s%s", s1, s2);
            if (!(u = id[s1])) {
                strcpy(name[cnt], s1);
                id[s1] = u = cnt++;
            }
                
            if (!(v = id[s2])) {
                strcpy(name[cnt], s2);
                id[s2] = v = cnt++;
            }
            add(u, v); add(v, u);
        }
        
        dfs(1, -1);
        int mm = 0x3f3f3f3f;
        for (i=1; i<=n; ++i) {
            if (mm > rcd[i]) {
                mm = rcd[i];
                ccnt = 0;
                mid[++ccnt] = i;
            } else if (mm == rcd[i]) mid[++ccnt] = i;
        }
        
        for (i=1; i<=ccnt; ++i) 
            vvvvv[i] = dfs2(mid[i], -1, 1);
    }
}te1, te2;

struct nobe {
    int id;
    ull val;
    bool operator < (const nobe &a) const {
        return val < a.val;
    }
    nobe () {}
    nobe (int iid, ull vval) : id(iid), val(vval) {}
};

void dfs3(int u1, int u2, int fa1, int fa2) {
    int i, v1, v2, tsz;
    ans[u1] = u2;
    vector<nobe> ve1, ve2;
    for (i=te1.head[u1]; i; i=te1.edge[i].lst) {
        v1 = te1.edge[i].to;
        if (v1 == fa1) continue;
        ve1.push_back(nobe(v1, te1.cnode[v1]));
    }
    for (i=te2.head[u2]; i; i=te2.edge[i].lst) {
        v2 = te2.edge[i].to;
        if (v2 == fa2) continue;
        ve2.push_back(nobe(v2, te2.cnode[v2]));
    }
    sort(ve1.begin(), ve1.end());
    sort(ve2.begin(), ve2.end());
    for (i=0, tsz=ve1.size(); i<tsz; ++i) 
        dfs3(ve1[i].id, ve2[i].id, u1, u2);
}

int main()
{
    int i, j, k, n;
    srand(time(NULL));
    for (i=0; i<maxn; ++i) x[i] = rand();
    while (~scanf("%d", &n)) {
        te1.init(n);
        te2.init(n);
        for (i=1; i<=te1.ccnt; ++i) 
            for (j=1; j<=te2.ccnt; ++j) {
                if (te1.vvvvv[i] == te2.vvvvv[j]) {
                    dfs3(te1.mid[i], te2.mid[j], te1.mid[i], te2.mid[j]);
                    for (k=1; k<=n; ++k) 
                        printf("%s %s\n", te1.name[k], te2.name[ans[k]]);
                    goto A;
                }
            }
        A: ;
    }
    
    return 0;
}

 

转载于:https://www.cnblogs.com/cgjh/p/9441605.html

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

(0)
编程小号编程小号

相关推荐

发表回复

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