• 树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 ]

  • 相关阅读:
    Python 三级菜单
    linux 下按文件类型删除
    linux 做内网端口映射
    ss
    fio
    libXtst.so.6 is needed by teamviewer-12.0.76279-0.i686
    copy 浅复制 与深复制
    Git 使用方法
    关于 爬虫使用 urllib.urlopen 提交默认 User-Agent值
    Python 官方模块文档
  • 原文地址:https://www.cnblogs.com/birchtree/p/14278139.html
Copyright © 2020-2023  润新知