Jzoj1155 有根树的同构(树的Rabin-Karp)
这里简单说一下rabin-karp
其实就是字符串hash算法,不理解的可以自行百度
对于一颗树,我们可以将其变为一个括号序列,对这个括号序列作rabin-karp,让后就可以轻松判断同构了是不是很简单
细节不多说,有一点必须注意:因为子树是无序的,所以dfs时必须对子树排序
#include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; #define SL __int128 #define BASE 313 SL pow(SL x,int k){ SL S=1; for(;k;x*=x,k>>=1) if(k&1) S*=x; return S; } struct HASH{ int l; SL v; //HASH(){ l=v=0; } }; bool operator < (HASH a,HASH b){ return a.v<b.v; } HASH operator + (HASH a,HASH b){ return (HASH){a.l+b.l,a.v*pow(BASE,b.l)+b.v}; } int cnt,h[1000],v[1000],nt[1000],f[1000],n,m; SL H[1000]; void adj(int x,int y){ v[++cnt]=y; nt[cnt]=h[x]; h[x]=cnt; } vector<HASH> ch[1000]; HASH dfs(int x){ HASH ans={0,0}; ch[x].clear(); for(int i=h[x];i;i=nt[i]) ch[x].push_back(dfs(v[i])); sort(ch[x].begin(),ch[x].end()); //这里非常重要! for(int i=0,z=ch[x].size();i<z;++i) ans=ans+ch[x][i]; ans=(HASH){1,'('}+ans+(HASH){1,')'}; return ans; } int main(){ scanf("%d%d",&m,&n); for(int k=1;k<=m;++k){ cnt=0; memset(f,0,sizeof f); memset(h,0,sizeof h); for(int x,y,i=1;i<n;++i){ scanf("%d%d",&x,&y); adj(x,y); f[y]=x; } for(int i=1;i<=n;++i) if(!f[i]) H[k]=dfs(i).v; } bool vis[1010]={0}; for(int i=1;i<=m;++i) if(!vis[i]){ vis[i]=1|printf("%d",i); for(int j=i+1;j<=m;++j) if(H[i]==H[j]) vis[j]=1|printf("=%d",j); puts(""); } return 0; }