&& hash tree isomorphic tutorial [BJOI2015] Tree

Topic Link

Rooted tree hash

Discrete Mathematics description of the hash tree in here . We can look at.

Determining whether there is a rooted tree with the structure, it can be considered a rooted tree coding. The encoding process, it is required to retain the tree morphological features, while ignoring the order of the different sub-tree. First look at this method:

You may wish to make a tree coding is a string \ (T \) .

For a point \ (U \) , first find the \ (U \) all \ (son_u \) encoding \ (son_u F_ {} \) , and then these coded in lexicographic order from small to large to give \ (g_ { . 1 \ K} cdots \) . Then \ (f_u = "0" + \ SUM \ Limits G_i + ". 1" \) .

So \ (T \) is encoded as a root node of coding.

You can verify the correctness of this algorithm by decoding the way.

This code is just numbers, is not considered a hash tree. This code ensures correctness. In fact, when we use usually does not and can not allow this (space is too much time). We usually modulo operations and methods will use the value. In fact, the value of the operation to meet as much as possible 保留树形态的特征,同时忽略子树顺序的不同. Addition, XOR, sorting, etc. are possible.

The method hash tree is very large, there are three common practice on OIwiki .

Unrooted tree hash

In general, by selecting the root unrooted trees turn into a rooted tree, thereby achieving encoding unrooted tree. The general Root center of the selected number. If there are two centers on selected coding small center root. For the truth is almost the same hash.

For this question, because the data range is very small, so the direct violence coding, map can be re-sentenced.

#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;
}

Guess you like

Origin www.cnblogs.com/chy-2003/p/11613061.html