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;
}