题目
Sample Input
输入1:
3
1 2
2 3
1 3
3 2
输入2:
4
1 2
2 3
3 4
1 2
1 3
1 4
Sample Output
输出1:
YES
1 3 2
输出2:
NO
题解
题目有两问,
1、判断树是否同构。
2、找出对应点。
对应第一问,考虑树的特征。
考虑每一个节点的特征有什么因素决定:
1、它儿子的特征
2、以它为根的子树大小
3、它的儿子个数
4、它的深度
现在就要把这些决定某个节点的因素变为一个东西。
设
fi
表示这个节点的特征值,
一般只有按照相同的规则将这些决定因素融合成一个数,
那么这个数就是它的特征值了,
建议几个数合并的时候不要用加法,可以选择异或,次方相乘等不容易相同的方法,还可以乘上相应的系数。
关于模数,建议使用c++中的unsigned long long
现在判断是否同构就只需要判断这两棵树的根节点的特征值是否相同就可以了,
而求一次树的特征值的复杂度是O(n),通过换根的方法就可以快速判断两棵树是否同构,并且找出他它们同构的根节点。
之后就是要将所有点一一对应了,递归处理,
对于一个点的所有儿子,将它们的特征值排序,然后跟另一棵树对应。
本题的关键就是如何将一棵树的特征快速地表现出来。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 100003
#define tt 23333
#define w 8888888
#define ull unsigned long long
using namespace std;
int n,m,nxt1[N*2],to1[N*2],b1[N],tot1,nxt2[N*2],to2[N*2],b2[N],tot2;
int son1[N],son2[N],si1[N],si2[N],x,y,ans[N],root;
ull f1[N],f2[N];
struct node
{
int x;
ull y;
}p1[N],p2[N],t;
bool cmp(node a,node b)
{
return a.y<b.y;
}
char ch;
void read(int& n)
{
n=0;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
for(;'0'<=ch && ch<='9';n=(n<<3)+(n<<1)+ch-48,ch=getchar());
}
ull F(ull x,ull y)
{
return (x*x*tt+y*y*tt)*(w+x+y);
}
void ins1(int x,int y)
{
nxt1[++tot1]=b1[x];
to1[tot1]=y;
b1[x]=tot1;
}
void ins2(int x,int y)
{
nxt2[++tot2]=b2[x];
to2[tot2]=y;
b2[x]=tot2;
}
void dfs1(int x,int fa)
{
si1[x]=1;
for(int i=b1[x];i;i=nxt1[i])
if(to1[i]!=fa)
{
dfs1(to1[i],x);
son1[x]++;
si1[x]+=si1[to1[i]];
f1[x]+=f1[to1[i]];
}
f1[x]=f1[x]+F(son1[x],si1[x]);
}
void dfs2(int x,int fa)
{
si2[x]=1;
for(int i=b2[x];i;i=nxt2[i])
if(to2[i]!=fa)
{
dfs2(to2[i],x);
son2[x]++;
si2[x]+=si2[to2[i]];
f2[x]+=f2[to2[i]];
}
f2[x]=f2[x]+F(son2[x],si2[x]);
}
void exchange(int x,int y)
{
f2[x]=f2[x]-f2[y]-F(son2[x],si2[x]);
son2[x]--;si2[x]-=si2[y];
f2[x]+=F(son2[x],si2[x]);
f2[y]-=F(son2[y],si2[y]);
son2[y]++;si2[y]=n;
f2[y]+=f2[x]+F(son2[y],si2[y]);
}
void work(int x,int fa)
{
if(f2[x]==f1[1])root=x;
if(root)return;
for(int i=b2[x];i;i=nxt2[i])
if(to2[i]!=fa)
{
exchange(x,to2[i]);
work(to2[i],x);
if(root)return;
exchange(to2[i],x);
}
}
void solve(int x1,int fa1,int x2,int fa2)
{
int ttt=0;
for(int i=b1[x1];i;i=nxt1[i])
if(to1[i]!=fa1)
{
t.x=to1[i];t.y=f1[t.x];
p1[++ttt]=t;
}
ttt=0;
for(int i=b2[x2];i;i=nxt2[i])
if(to2[i]!=fa2)
{
t.x=to2[i];t.y=f2[t.x];
p2[++ttt]=t;
}
sort(p1+1,p1+1+son1[x1],cmp);
sort(p2+1,p2+1+son2[x2],cmp);
for(int i=1;i<=son1[x1];i++)
ans[p1[i].x]=p2[i].x;
for(int i=b1[x1];i;i=nxt1[i])
if(to1[i]!=fa1)solve(to1[i],x1,ans[to1[i]],x2);
}
int main()
{
freopen("check.in","r",stdin);
freopen("check.out","w",stdout);
read(n);
for(int i=1;i<n;i++)
read(x),read(y),ins1(x,y),ins1(y,x);
for(int i=1;i<n;i++)
read(x),read(y),ins2(x,y),ins2(y,x);
dfs1(1,0);
dfs2(1,0);
root=0;
work(1,0);
if(root==0)
{
printf("NO\n");
return 0;
}
ans[1]=root;
solve(1,0,root,0);
printf("YES\n");
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}