bzoj 4474: [Jsoi2015]isomorphism

来源:互联网 发布:笑郭网络验证教程 编辑:程序博客网 时间:2024/05/01 12:51

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
原创粉丝点击