bzoj 4474: [Jsoi2015]isomorphism

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

Sample Output

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值