1. 程式人生 > >【bzoj 4337】樹的同構

【bzoj 4337】樹的同構

傳送門~

解題思路

樹同構模板題。
為了保險用了雙雜湊。
選了極其暴力的方法處理兩個重心的情況:對於每個重心分別求雜湊值然後取max。
雜湊的時候,每次將所有子節點的雜湊值排好序拿出來,然後看心情瞎搞,隨便乘一乘模一模,最後將根節點的雜湊值作為整棵樹的雜湊值。
程式碼:

#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
using namespace std; struct tree{ int hed[55],nex[105],lb[105]; int w1[55][55],w2[55][55]; int h1[55],h2[55],ha1,ha2; int u[5],n,root,tot,lo; void add(int x,int y){ lo++; nex[lo]=hed[x]; hed[x]=lo; lb[lo]=y; } void read(){ int x; memset
(hed,0,sizeof(hed)); ha1=ha2=tot=lo=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&x); if(!x) root=i; else {add(x,i);add(i,x);} } } int getu(int x,int fa){ int siz=1,flag=0; for(int i=hed[x];i!=0
;i=nex[i]) if(lb[i]!=fa){ int r0=getu(lb[i],x); if(r0*2>n) flag=1; siz+=r0; } if((n-siz)*2>n) flag=1; if(!flag) u[++tot]=x; return siz; } void ha(int x,int fa){ h1[x]=17;h2[x]=59; int len=0; for(int i=hed[x];i!=0;i=nex[i]) if(lb[i]!=fa){ ha(lb[i],x);len++; w1[x][len]=h1[lb[i]]; w2[x][len]=h2[lb[i]]; } if(!len) return ; sort(w1[x]+1,w1[x]+len+1); sort(w2[x]+1,w2[x]+len+1); for(int i=1;i<=len;i++) h1[x]=(h1[x]*19260%817+w1[x][i]*17%233)%1777; for(int i=1;i<=len;i++) h2[x]=(h2[x]*83374%294+w2[x][i]*40%332)%1443; } void solve(){ read(); int r=getu(root,root); for(int i=1;i<=tot;i++){ ha(u[i],u[i]); ha1=max(ha1,h1[u[i]]); ha2=max(ha2,h2[u[i]]); } } bool operator == (const tree p) const{ return (ha1==p.ha1 && ha2==p.ha2); } }T[55]; int m; int main(){ scanf("%d",&m); for(int i=1;i<=m;i++) T[i].solve(); for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) if(T[i]==T[j]) {printf("%d\n",j);break;} return 0; }