Description
一个无向树的度数为 2的结点称为假结点,其它结点称为真结点。一个无向树的简化树
其结点由原树的全体真结点组成,两个真结点之间有边当且仅当它们在原树中有边,或者在
原树中有一条联结这两个结点的路,其中间节点全是假结点。两个无向树各自的简化树如果
同构,即存在结点之间的一一对应,使得在一个树中的任意两个结点之间有边当且仅当它们
的对应结点在另一个树中有边,则称原来的两个无向树实质同构。给定若干个无向树,将相
互实质同构的无向树只保留一个其余删除。统计剩下的相互不实质同构的无向树个数,并将
它们的简化树结点个数从小到大输出。
Input
第一行只有一个正整数 m,后面依次输入m个无向树,每个无向树先用一行输入结点个
数n,结点就用1到n表示,然后用n-1行输入n-1条无向边,每行有两个 1到n 之间的不
同的正整数,用一个空格隔开,代表这两个结点之间有无向边。两个树之间无空行。
2<=m<=20, 2<=n<=10000
Output
第一行输出一个正整数,即输入中不计实质同构包含无向树的个数 m0(1<=m0<=m)。第
二行包含不严格递增的 m0个正整数,表示这m0个无向树的简化树结点个数。相邻两数用一
个空格隔开。
Sample Input
2
4
1 4
2 4
3 4
5
1 3
2 3
3 4
4 5
4
1 4
2 4
3 4
5
1 3
2 3
3 4
4 5
Sample Output
1
4
4
似乎有一种可以判断树的同构的算法。不过我并不会。
写了个近似树hash的东西。记录了各种东西。
不知道有没有反例。。因为原题的数据比较弱。似乎只要随便多记录几种值比较就可以过了
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
int next;
}a[202001];
int head[101001];
int edge;
inline void add(int s,int t)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
}
int dge[10001],dgee[10001];
int sux[21][10001],sumx[21][10001];
int anx[21][10001],ansx[21][10001];
int s[10001],sx[10001];
int ss[10001],tt[10001];
bool v[10001];
inline bool cmp(int x,int y)
{
if(x>y)
return true;
return false;
}
inline int dfs(int d)
{
v[d]=true;
if(dge[d]!=0)
return dge[d];
int ans=0;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
ans+=dfs(t);
}
return ans;
}
int main()
{
// freopen("isomorphism.in","r",stdin);
// freopen("isomorphism.out","w",stdout);
int n,m;
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
{
scanf("%d",&m);
memset(dge,0,sizeof(dge));
memset(dgee,0,sizeof(dgee));
edge=0;
memset(head,0,sizeof(head));
memset(a,0,sizeof(a));
for(j=1;j<=m-1;j++)
{
scanf("%d%d",&ss[j],&tt[j]);
edge++;
add(ss[j],tt[j]);
edge++;
add(tt[j],ss[j]);
dge[ss[j]]++;
dge[tt[j]]++;
}
for(j=1;j<=m;j++)
if(dge[j]==2)
dge[j]=0;
for(j=1;j<=m-1;j++)
{
memset(v,false,sizeof(v));
v[ss[j]]=true;
dgee[dge[ss[j]]]+=dfs(tt[j]);
memset(v,false,sizeof(v));
v[tt[j]]=true;
dgee[dge[tt[j]]]+=dfs(ss[j]);
}
for(j=1;j<=m;j++)
sumx[i][j]=dgee[j];
sort(dge+1,dge+1+m,cmp);
for(j=1;j<=m;j++)
{
if(dge[j]==0)
break;
sux[i][j]=dge[j];
s[i]++;
}
}
int k;
int p=0;
for(i=1;i<=n;i++)
{
bool flag=true;
for(j=1;j<=p;j++)
{
if(s[i]!=sx[j])
continue;
bool fx=true;
for(k=1;k<=10000;k++)
{
if(sux[i][k]!=anx[j][k]||sumx[i][k]!=ansx[j][k])
{
fx=false;
break;
}
}
if(fx)
{
flag=false;
break;
}
}
if(flag)
{
p++;
for(j=1;j<=10000;j++)
{
anx[p][j]=sux[i][j];
ansx[p][j]=sumx[i][j];
}
sx[p]=s[i];
}
}
printf("%d\n",p);
sort(sx+1,sx+1+p);
printf("%d",sx[1]);
for(i=2;i<=p;i++)
printf(" %d",sx[i]);
printf("\n");
return 0;
}