版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82951244
传送门
解析:
其实这道题数据可以再大一点,再大一点的话,括号序列加个哈希就能过了。
由于数据较小,我选择的是伪的最小表示法加上括号序列。
思路:
括号序列是
序的一个变种。
在
进入一个点的时候,序列中加入一个“(”,再遍历完该节点的所有子树时候(即退出该节点时),序列中加入一个“)”。那么显然每一种括号序列唯一对应原来的树的形态。与标号无关,非常适合解决这道题。
而同构的树可以通过选择不同的根和子树遍历顺序得到不同的括号序列。
所以这道题的突破点有两个,选择合适的根和遍历顺序。
随便推一下发现,每一个大括号里面包含的次级括号表示的是它子树的遍历情况,而且整体交换次级括号的顺序不会影响树的形态,所以我们考虑将每个子树遍历得到的括号序列排个序,这就是伪的最小表示法(逃。。。
而50个节点,不可能每个都当做根遍历一遍吧(虽然说这道题小数据貌似有人卡过去了。。。),数据大一点可能就出事了。
我们考虑选择重心,因为重心可以 求出,并且一棵树至多只有两个重心,我们选择两个重心都 求出最小的括号序列,选择更小的一个就是这棵树对应的括号序列。
这样可以证明,同构的树对应的括号序列是一致的。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(int a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=55;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline
void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int n,m;
int siz[N];
int f[N];
string h[N],ans[N];
int maxn;
inline
void getroot(int u,int fa){
siz[u]=1;
f[u]=0;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa)continue;
getroot(v,u);
siz[u]+=siz[v];
if(siz[v]>f[u])f[u]=siz[v];
}
f[u]=max(f[u],n-siz[u]);
maxn=min(maxn,f[u]);
}
inline
void dfs(int u,int fa){
h[u]="(";
vector<string> ss;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa)continue;
dfs(v,u);
ss.push_back(h[v]);
}
sort(ss.begin(),ss.end());
for(vector<string>::iterator it=ss.begin();it!=ss.end();++it){
h[u]+=*it;
}
h[u]+=")";
}
signed main(){
m=getint();
for(int re t=1;t<=m;++t){
n=getint();
ecnt=0;
memset(last,0,sizeof last);
for(int re i=1;i<=n;++i){
int x=getint();
if(x)addedge(i,x);
}
maxn=n;
getroot(1,0);
string tmp="";
for(int re i=1;i<=n;++i)if(f[i]==maxn){
dfs(i,0);
if(h[i]<tmp||tmp=="")tmp=h[i];
}
ans[t]=tmp;
for(int re i=1;i<=t;++i)
if(ans[i]==ans[t]){
outint(i),pc('\n');
break;
}
}
return 0;
}