1. 程式人生 > >【bzoj4337】【Bjoi2015】樹的同構

【bzoj4337】【Bjoi2015】樹的同構

  • 題解

    • 無標號樹的HASH:
    • 找到樹的重心,以重心為根求出括號序列;
    • 由於樹的重心最多隻有兩個,取字典序的最小括號序列HASH即可
    • 樹的括號序列$s_{u}="(s_{v_{1}},s_{v_{2}},s_{v_{3}},...,s_{v_{n}})"$,同時字典序$s_{v_{1}} <= s_{v_{2}} <= ,... $ 
    • 有標號樹的HASH:
    • 個人認為可以直接$prufer$序列$HASH$
    • 或者直接將兒子排個序$hash$,(總之亂搞
    •  1 #include<bits/stdc++.h>
       2 #define ll long long
       3 #define mod 998244353
       4 using namespace std;
       5 const int N=51;
       6 int n,m,hd[N],o,sz[N],mx[N],Mx,tot;
       7 struct Edge{int v,nt;}E[N<<1];
       8 map<int,int>h;
       9 string now,s[N],tmp[N];
      10 void adde(int u,int v){
      
      11 E[o]=(Edge){v,hd[u]};hd[u]=o++; 12 E[o]=(Edge){u,hd[v]};hd[v]=o++; 13 } 14 void get_rt(int u,int fa){ 15 sz[u]=1;mx[u]=0; 16 for(int i=hd[u];~i;i=E[i].nt){ 17 int v=E[i].v; 18 if(v==fa)continue; 19 get_rt(v,u); 20 sz[u]+=sz[v]; 21 mx[u]=max(mx[u],sz[v]);
      22 } 23 mx[u]=max(m-sz[u],mx[u]); 24 if(mx[u]<Mx)Mx=mx[u]; 25 } 26 void dfs(int u,int fa){ 27 s[u]="("; 28 for(int i=hd[u];~i;i=E[i].nt){ 29 int v=E[i].v; 30 if(v==fa)continue; 31 dfs(v,u); 32 } 33 tot=0; 34 for(int i=hd[u];~i;i=E[i].nt){ 35 int v=E[i].v; 36 if(v==fa)continue; 37 tmp[++tot]=s[v]; 38 } 39 sort(tmp+1,tmp+tot+1); 40 for(int i=1;i<=tot;i++)s[u]=s[u]+tmp[i]; 41 s[u]+=")"; 42 } 43 int main(){ 44 #ifndef ONLINE_JUDGE 45 freopen("bzoj4337.in","r",stdin); 46 freopen("bzoj4337.out","w",stdout); 47 #endif 48 scanf("%d",&n); 49 for(int I=1;I<=n;I++){ 50 o=1;memset(hd,-1,sizeof(hd)); 51 scanf("%d",&m); 52 for(int i=1,x;i<=m;i++){ 53 scanf("%d",&x); 54 if(x)adde(x,i); 55 } 56 Mx=m;get_rt(1,0); 57 now=""; 58 for(int i=1;i<=m;i++)if(Mx==mx[i]){ 59 dfs(i,0); 60 if(now<s[i])now=s[i]; 61 } 62 ll x=0; 63 for(int i=0;i<(int)now.length();i++){ 64 x = ((x<<1) + now[i])%mod; 65 } 66 //printf("%s\n",now.c_str()); 67 if(!h[x])h[x]=I; 68 printf("%d\n",h[x]); 69 } 70 return 0; 71 }
      bzoj4337