zoukankan      html  css  js  c++  java
  • 树Hash学习笔记

    树Hash学习笔记

    树Hash是用来判断两棵树是否同构(即去掉编号后形态一样的方法)

    子树无顺序的树同构

    子树排列顺序不同,算一种树。

    对于有根树,我们从根开始DFS,对每个子树维护哈希值(h_x)对于同构的树,他们根节点的(h)一定相同。
    一个比较好的递推方法是:

    [h_x=1+sum_{y in son(x)} h_ycdot P(sz_y) ]

    其中(P(i))表示第(i)个质数,(sz_x)表示(x)的子树大小.这样可以减少冲突。

    对于无根树,我们需要定一个根,且这个根的选择不会随着编号的变化而变化。那么就可以选择树的重心来DFS.如果有两个重心,就把Hash值分别取(max)(min).
    当然,也可以求出以每个点为根的DP值,类似树形DP中的换根法,复杂度(O(n))

    vint root=0;
    int sz[maxn+5],f[maxn+5];
    void dfs1(int x,int fa){//重心不会因为编号方式改变,以它为根可减少误判 
    	sz[x]=1;
    	for(int i=head[x];i;i=E[i].next){
    		int y=E[i].to;
    		if(y!=fa){
    			dfs1(y,x);
    			sz[x]+=sz[y];
    			f[x]=max(f[x],sz[y]); 
    		} 
    	}
    	f[x]=max(f[x],n-sz[x]);
    	if(f[x]<f[root]||root==0) root=x;
    }
    ll hsh[maxn+5];
    void dfs2(int x,int fa){
    	sz[x]=1;
    	hsh[x]=1;
    	for(int i=head[x];i;i=E[i].next){
    		int y=E[i].to;
    		if(y!=fa){
    			dfs2(y,x);
    			hsh[x]+=hsh[y]*prime[sz[y]];
    			sz[x]+=sz[y];
    		}
    	}
    }
    

    换根

    	void dfs3(int x,int fa){//求出以每个点为根的hash值 
    		for(int i=0;i<T[x].size();i++){
    			int y=T[x][i];
    			if(y!=fa){
    				hshRt[y]=(hshRt[x]-hsh[y]*prime[sz[y]])*prime[totsz-sz[y]]+hsh[y];
    				dfs3(y,x);
    			}
    		}
    	}
    

    当然,由于树Hash的本质仍然是哈希,有时可能会被卡。此时可以对h取模(或自然溢出),或random_shuffle()质数数组,或改变对应关系

    子树有顺序的树同构

    由于不能随便交换子树(比如圆方树的同构),我们可以类似字符串hash的方法,按顺序把每个子树的hash值当做字符

    [h_x=(h_x cdot P+h_y)mod M ]

  • 相关阅读:
    mysql5.5 uuid做主键与int做主键的性能实测
    dom4j解析xml字符串实例
    spring自动注入是单例还是多例?单例如何注入多例?
    Spring中Bean的五个作用域
    【总结】瞬时高并发(秒杀/活动)Redis方案
    浅谈分布式事务
    基于Redis实现分布式锁
    MySQL事务隔离级别详解
    Redis学习手册(Sorted-Sets数据类型)
    Redis的快照持久化-RDB与AOF
  • 原文地址:https://www.cnblogs.com/birchtree/p/14278139.html
Copyright © 2011-2022 走看看