【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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值