BZOJ4337 : BJOI2015 树的同构

本文介绍了一种寻找无根树重心的方法,并通过枚举重心构建有根树的最小表示。使用括号序列来表示每棵树,并通过排序子树序列实现字典序最大化的构造。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于一棵无根树,它的重心个数不超过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;
}

  

转载于:https://www.cnblogs.com/clrs97/p/4982839.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值