[题意]
一个城市的铁路线构成一棵树,但是现在车站(顶点)的名字变了,但是铁路线(树)的结构没有变。现在给定原来的结构和现在的结构,确定新旧顶点间的对应关系。
[分析]
树的同构判断
自己没什么想法,看题解说的树hash,方法应该很多(都不会
只记得以前做过一道题,hash了字典树,方法也是抄的别人的。。。
所以这里直接采用了题解提供的策略,即:
先求树的中点(有2个中点的都试一下),将中点作为根
对于每颗树,将它的子树按hash值大小排序,则
hash[root]=(∑Pi∗hash[i])%Q
其中P是比较大的质数,Q是特别大的质数
然后乱搞就可以了,细节特别多,只有自己体会了,wa了一天(最后发现是hash冲突。。乱取了一通质数,无限wa,最后Q随便乱输了一个[都不知道是不是质数],就过了。。。
[代码]
#include <bits/stdc++.h>
using namespace std ;
const int N = 100000 + 5 ;
typedef long long LL ;
const LL Q = 5465464659 ;
const LL P = 1e7 + 7 ;
int n ;
char s[20] , t[20] ;
int match[N] ;
LL powMod( LL a , LL b )
{
LL r = 1 ;
while( b )
{
if( b&1 ) r = r*a%Q ;
b >>= 1 ;
a = a*a%Q ;
}
return r ;
}
struct Tree
{
int n , cnt , sz[N] ;
map<string,int> id ;
vector<string> name ;
struct node
{
int u ; LL hash ;
node( int _u , LL _h = 1 ):u(_u),hash(_h) { }
bool operator < ( const node &rhs ) const
{
return hash < rhs.hash ;
}
} ;
vector<node> G[N] ;
pair<int,int> mid ;
int getId( string &s )
{
if( id.count(s) ) return id[s] ;
name.push_back(s) ;
return id[s] = ++cnt ;
}
void init( int _n )
{
n = _n ; cnt = 0 ; mid.first = mid.second = 0 ;
id.clear() ; name.clear() ; name.push_back("") ;
for( int i = 1 ; i <= n ; i++ )
G[i].clear() ;
for( int i = 1 ; i < n ; i++ )
{
scanf( "%s%s" , s , t ) ;
string ss = s , tt = t ;
int u = getId(ss) , v = getId(tt) ;
G[u].push_back(node(v)) ;
G[v].push_back(node(u)) ;
}
}
void getMid( int u = 1 , int pre = 0 )
{
sz[u] = 1 ;
bool is = 1 ;
for( auto &it : G[u] )
{
int v = it.u ;
if( v == pre ) continue ;
getMid(v,u) ;
is &= (sz[v] <= n/2) ;
sz[u] += sz[v] ;
}
is &= ((n-sz[u]) <= n/2) ;
if( !is ) return ;
if( mid.first )
mid.second = u ;
else
mid.first = u ;
}
LL getHash( int u , int pre = 0 )
{
if( G[u].size() == 1 )
return 1 ;
for( auto &it : G[u] )
{
int v = it.u ;
if( v == pre ) continue ;
it.hash = getHash(v,u) ;
}
sort(G[u].begin(),G[u].end()) ;
LL code = 0 ; int k = 0 ;
for( auto &it : G[u] )
{
int v = it.u ;
if( v == pre ) continue ;
code = ( code + it.hash*powMod(P,++k)%Q ) % Q ;
}
return code ;
}
} A , B ;
bool getMap( int u1 , int u2 , int pre1 = 0 , int pre2 = 0 )
{
match[u1] = u2 ;
auto &G1 = A.G[u1] , &G2 = B.G[u2] ;
for( int i = 0 , j = 0 ; i < G1.size() && j < G2.size() ; )
{
int v1 = G1[i].u , v2 = G2[j].u ;
if( v1 == pre1 )
{
i++ ;
continue ;
}
if( v2 == pre2 )
{
j++ ;
continue ;
}
getMap(v1,v2,u1,u2) ;
i++ , j++ ;
}
return 1 ;
}
bool solve( int u1 , int u2 )
{
if( A.getHash(u1) != B.getHash(u2) )
return 0 ;
getMap(u1,u2) ;
for( int i = 1 ; i <= n ; i++ )
printf( "%s %s\n" , A.name[i].c_str() , B.name[match[i]].c_str() ) ;
return 1 ;
}
int main()
{
while( ~scanf( "%d" , &n ) )
{
A.init(n) ;
B.init(n) ;
A.getMid() ;
B.getMid() ;
if( !solve(A.mid.first,B.mid.first) )
solve(A.mid.first,B.mid.second) ;
}
return 0 ;
}