给出 m 棵无根树,求每棵树 i 的同构的树(长得一样)的最小编号。
题目骗人QAQ,明明是无根树,还搞个根节点。怎么判断同构?Hash大法好!
比较好的Hash方法是给每个儿子都对应一个素数(可以提前打表搞出 50 个素数),需要注意的是要将儿子按照权值排序,这样才能才能正确判断树的同构。
#include
#include
#include
using namespace std;
typedef unsigned long long ULL;
const int maxn=50,maxm=50,Base=23333;
const int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229};
int m,ro,n[maxm+5];ULL ha[maxm+5][maxn+5];
int E,lnk[maxn*2+5],nxt[maxn*2+5],son[maxn*2+5];
inline void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}
ULL Dfs(int x,int fa=0)
{
int tot=0;ULL now[maxn+5],v=Base;
for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa) now[tot++]=Dfs(son[j],x);
sort(now,now+tot);for (int i=0;ireturn v;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d",&n[i]);E=0;memset(lnk,0,sizeof(lnk));
for (int j=1,x;j<=n[i];j++)
{scanf("%d",&x);if (x) Add(x,j),Add(j,x);}
for (int j=1;j<=n[i];j++) ha[i][j]=Dfs(j);sort(ha[i]+1,ha[i]+1+n[i]);
for (int j=1,k;j<=i;j++) if (n[i]==n[j])
{
for (k=1;k<=n[i];k++) if (ha[i][k]!=ha[j][k]) break;
if (k>n[i]) {printf("%d\n",j);break;}
}
}
return 0;
}