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


posted @ 2017-09-19 19:52  扩展的灰(Extended_Ash)  阅读(141)  评论(0编辑  收藏  举报