mark一下:
对于一个有根树,我们可以通过比较他们的括号序列的最小表示,如果他们的括号序列最小表示完全相等,那么他们同构。
https://www.byvoid.com/blog/directed-tree-bracket-sequence
dfs进入某个子树用 '(' 表示,dfs结束用')'表示,这样就将一颗树转化成一个括号序列。
只需将括号序列变成最小表示,就可以比较两棵树是否同构。但复杂度好像很高的样子...
回到树上来说,比较两棵子树的大小,可以先比较两个顶点的度,如果度相等,则递归比较子树。则可以看成是求一个最小的度序列。
括号序列的另一个理解,就是poj上某道题。'('可以看成0,可以理解为向远离根节点的节点走,')'可以看成1,回溯,往回走。
于是比较两棵子树的大小,可以将两个01序列,看做为字符串,求最小表示。
不管是哪种序列,都可以作为树的最小表示。序列求出来,我们可以用 子序列排序+hash 得到一个新的序列,最后得到树的最小表示hash值。复杂度nlogn。
快速的算法可以参考 <Hash在信息学竞赛中的一类应用-杨弋>。
无根树可以通过一次拓扑排序,将整棵树收缩,最后只剩下一个点或者是两个点。枚举根即可。
贴一下UVA 12489 - Combating cancer 的代码,一脸水过的样子,不知道为什么用度序列hash连样例都过不了,01序列hash就过了。
hash函数找CJboy要的一个字符串hash的函数,不明觉厉~~
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<map> #include<queue> #include<iostream> using namespace std; #define For(i,forN) for(int i=0;i<forN;i++) #define ForEdge(i,u) for(int i=head[u];i!=-1;i=edge[i].next) #define sf scanf #define pf printf #define mp make_pair #define _clr(x,y) memset(x,(y),sizeof(x)) typedef unsigned int UI ; const int Maxn=21000,Mod=2081,hx=557,hy=131; /* 判断树的同构,用此hash函数: */ int head[Maxn],etot,Cc[Maxn]; int n; UI Hash[Maxn]; bool vis[Maxn]; struct Edge { int to,next; }edge[Maxn*2]; void init_edge() { etot=0; _clr(head,-1); } void add_edge(int u,int v) { edge[etot].to=v; edge[etot].next=head[u]; head[u]=etot++; } void dfs(int u) { vis[u]=true; vector < int > Ve; ForEdge(i,u) { int v=edge[i].to; if(!vis[v]) { dfs(v); Ve.push_back(Hash[v]); } } sort(Ve.begin(),Ve.end()); Ve.push_back(1);//可以看做字符')',或者1 UI b = 378551 , a = 63689; Hash[u]=0;//可以看做字符'(',或者0 For(i,Ve.size()) { Hash[u]=Hash[u]*a+Ve[i]; a*=b; } Hash[u]&=0x7FFFFFFF; } int din[Maxn],stk[Maxn],top; int ans[2][2]; int main() { while(~sf("%d",&n)) { int tid[2]={0}; for(int cas=0;cas<2;cas++) { init_edge(); int u,v; queue < int > q; _clr(din,0); for(int i=1;i<n;i++) { sf("%d%d",&u,&v); din[u]++,din[v]++; add_edge(u,v); add_edge(v,u); } int last=n; _clr(vis,false); for(int i=1;i<n+1;i++) { if(din[i]==1) q.push(i),last--,vis[i]=true; } while(last!=0 && !q.empty()) { u=q.front(); q.pop(); din[u]--; ForEdge(i,u) { int v=edge[i].to; if(!vis[v]) { din[v]--; if(din[v]==1) q.push(v),last--,vis[v]=true; } } } for(int i=1;i<=n;i++) { if(din[i]==1) { _clr(vis,false); dfs(i); ans[cas][tid[cas]++]=Hash[i]; if(tid[cas]>2) while(1); } } } bool flag=false; for(int i=0;i<tid[0];i++) for(int j=0;j<tid[1];j++) if(ans[0][i] == ans[1][j]) flag=true; if(flag) puts("S"); else puts("N"); } return 0; }