[BJOI2015]树的同构 && 树哈希教程

Posted chy-2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BJOI2015]树的同构 && 树哈希教程相关的知识,希望对你有一定的参考价值。

题目链接

有根树的哈希

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

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

不妨令一棵树的编码是个字符串\(T\)

对于一个点\(u\),先求出\(u\)所有\(son_u\)的编码\(f_son_u\),然后将这些编码按字典序从小到大排序得到\(g_1\cdots k\)。那么\(f_u="0"+\sum\limits 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\n", Map[ S ] );
    
    return 0;

以上是关于[BJOI2015]树的同构 && 树哈希教程的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ4337][BJOI2015]树的同构(树的最小表示法)

[BJOI2015]树的同构

bzoj 4337[BJOI2015]树的同构 - 括号序列

P5043 模板树同构([BJOI2015]树的同构)

luogu P5043 模板树同构([BJOI2015]树的同构)

bzoj4337 BJOI2015 树的同构