BZOJ4337 : BJOI2015 树的同构
对于一棵无根树,它的重心个数不超过2。
枚举每个重心,以重心为根求出这棵有根树的最小表示,然后取字典序最大的即可。
对于有根树的最小表示,可以看成括号序列,每次把子树的括号序列按字典序排序后依次串连起来即可。
#include<cstdio> #include<string> #include<algorithm> #define N 55 using namespace std; int T,n,i,j,k,x,g[N],v[N<<1],nxt[N<<1],ed,f[N],son[N],mx;string h[N],q[N],val[N]; inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void findroot(int x,int y){ son[x]=1;f[x]=0; for(int i=g[x];i;i=nxt[i])if(v[i]!=y){ findroot(v[i],x); son[x]+=son[v[i]]; if(son[v[i]]>f[x])f[x]=son[v[i]]; } if(n-son[x]>f[x])f[x]=n-son[x]; if(f[x]<mx)mx=f[x]; } void dfs(int x,int y){ h[x]="("; for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x); int t=0; for(int i=g[x];i;i=nxt[i])if(v[i]!=y)q[t++]=h[v[i]]; if(t>1)std::sort(q,q+t); for(int i=0;i<t;i++)h[x]+=q[i]; h[x]+=")"; } string solve(){ int i;string t=""; scanf("%d",&n); for(ed=0,mx=n,i=1;i<=n;i++)g[i]=0; for(i=1;i<=n;i++){ scanf("%d",&x); if(x)add(i,x),add(x,i); } findroot(1,0); for(i=1;i<=n;i++)if(f[i]==mx){ dfs(i,0); if(h[i]>t)t=h[i]; } return t; } int main(){ scanf("%d",&T); for(i=1;i<=T;i++)val[i]=solve(); for(i=1;i<=T;printf("%d\n",k),i++)for(j=k=i;j;j--)if(val[j]==val[i])k=j; return 0; }