zoukankan      html  css  js  c++  java
  • [BJOI2015]树的同构 && 树哈希教程

    题目链接

    有根树的哈希

    离散数学中对树哈希的描述在这里。大家可以看看。

    判断有根树是否同构,可以考虑将有根树编码。而编码过程中,要求保留树形态的特征,同时忽略子树顺序的不同。先来看一看这个方法:

    不妨令一棵树的编码是个字符串$T$。

    对于一个点$u$,先求出$u$所有$son_u$的编码$f_$,然后将这些编码按字典序从小到大排序得到$g_{1cdots k}$。那么$f_u="0"+sumlimits g_i+"1"$。

    令$T$的编码为根节点的编码。

    通过解码的方式可以验证这个算法的正确性。

    这个只是树的编码,并不算是树的哈希。这个编码保证了正确性。而实际上,我们应用的时候,通常不会,也不允许这样做(时间空间都吃不消)。我们通常会采用数值的操作和取模的方法。而实际上,这个数值的操作要尽可能满足保留树形态的特征,同时忽略子树顺序的不同。加法、异或、排序等都是可以的。

    树哈希的方法非常多,OIwiki上有三种常见的做法

    无根树的哈希

    一般的,通过选定根将无根树转成有根树,从而实现无根树的编码。而根一般选定为数的中心。如果有两个中心,就选定编码较小中心为根。对于哈希也是差不多的道理。

    对于这道题,由于数据范围十分小,所以直接暴力编码,map判重即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int Maxn = 60;
    struct edge {
    	int To, Next;
    	edge() {}
    	edge( int _To, int _Next ) : To( _To ), Next( _Next ) {}
    };
    int Start[ Maxn ], Used;
    edge Edge[ Maxn << 1 ];
    inline void AddEdge( int x, int y ) {
    	Edge[ ++Used ] = edge( y, Start[ x ] );
    	Start[ x ] = Used;
    	return;
    }
    
    map< string, int > Map;
    string A[ Maxn ], B[ Maxn ], S;
    int n, m, T[ Maxn ];
    int Cnt, Rt[ Maxn ];
    
    int Dfs1( int u, int Fa ) {
    	int Size = 1, IsR = 1;
    	for( int t = Start[ u ]; t; t = Edge[ t ].Next ) {
    		int v = Edge[ t ].To;
    		if( v == Fa ) continue;
    		int T = Dfs1( v, u );
    		if( T > n / 2 ) IsR = 0;
    		Size += T;
    	}
    	if( n - Size > n / 2 ) IsR = 0;
    	if( IsR ) Rt[ ++Cnt ] = u;
    	return Size;
    }
    
    void Cal( int u, int Fa ) {
    	for( int t = Start[ u ]; t; t = Edge[ t ].Next ) {
    		int v = Edge[ t ].To;
    		if( v == Fa ) continue;
    		Cal( v, u );
    	}
    	A[ u ] = "0";
    	int Cnt = 0;
    	for( int t = Start[ u ]; t; t = Edge[ t ].Next ) {
    		int v = Edge[ t ].To;
    		if( v == Fa ) continue;
    		B[ ++Cnt ] = A[ v ];
    	}
    	sort( B + 1, B + Cnt + 1 );
    	for( int i = 1; i <= Cnt; ++i )
    		A[ u ] = A[ u ] + B[ i ];
    	A[ u ] = A[ u ] + "1";
    	return;
    }
    
    int main() {
    	scanf( "%d", &m );
    	for( int i = 1; i <= m; ++i ) {
    		memset( Start, 0, sizeof( Start ) );
    		Used = 0;
    		scanf( "%d", &n );
    		for( int j = 1; j <= n; ++j ) {
    			int x;
    			scanf( "%d", &x );
    			if( x == 0 ) continue;
    			AddEdge( x, j );
    			AddEdge( j, x );
    		}
    		Cnt = 0;
    		Dfs1( 1, 0 );
    		Cal( Rt[ 1 ], 0 );
    		S = A[ Rt[ 1 ] ];
    		for( int j = 2; j <= Cnt; ++j ) {
    			Cal( Rt[ j ], 0 );
    			if( A[ Rt[ j ] ] < S )
    				S = A[ Rt[ j ] ];
    		}
    		if( Map.find( S ) == Map.end() ) Map[ S ] = i;
    		printf( "%d
    ", Map[ S ] );
    	}
    	return 0;
    }
    
  • 相关阅读:
    ASP.net 上传
    asp.net 上传
    asp.net dropdownlist和listbox
    jqeury之平移轮播
    vs2013的asp.net 管理
    jqeury轮播
    jqeury之轮播图
    重温委托(delegate)和事件(event)
    Log4Net
    解决SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT'OpenRowset/OpenDatasource' 的访问的方法
  • 原文地址:https://www.cnblogs.com/chy-2003/p/11613061.html
Copyright © 2011-2022 走看看