题目连接
- 该题是luogu试炼场的2-14:T4
题目大意
- 给出一棵树;
- 求最大的对称子树的规模
题目分析
- 对称树:以某个节点为根,一直延伸到叶子,完全对称
- 我的读题最大误解,因为下面的样例:
上图的样例给了我一个极大的误导,以为是蓝色框和绿色框两个子树对称,所以“对称子树的单边值”是3。
- 正解应该是下图:
上图红框中的子树内部对称,所以对称的子树节点总数是3。
解题思路:
- 扫描所有n个节点,深搜比较他们的左右儿子(类似建堆的思维);
- 如下图:对于当前父节点 id=10 ,如果左儿子 s1:id=7,右儿子 s2:id=8相同,则比较 (s1的左儿子 id=3,s2的右儿子id=6)和 (s1的右儿子id=4,s2的左儿子id=5);
4. 用一个标签 f 作为记录,如果递推到叶子,都完全相同,则该子树是对称子树。
5. 对于该子树,用一个简单的深搜,算出节点数量。
代码:
//luogu5018:对称二叉树
//树的对称性
//暴力枚举
#include<bits/stdc++.h>
using namespace std;
const int mx=1e6+5;
int n,ans=1,f;
struct tre{int s1,s2,v,s;tre(){s1=s2=v=-1;s=1;};}a[mx];
void dfs(int x,int y)
{
if(x==-1&&y==-1) return ;//到叶子了叶子
if(x==-1||y==-1||a[x].v!=a[y].v) { f=0; return ; }//不对称
dfs(a[x].s1,a[y].s2);
dfs(a[x].s2,a[y].s1);
}
int cnt(int x)//计算子节点数量(含根)
{
int s=1;//自己(根)
if(a[x].s1!=-1) s+=cnt(a[x].s1);
if(a[x].s2!=-1) s+=cnt(a[x].s2);
return s;
}
int main()
{
scanf("%d",&n);
//存值
for(int i=1;i<=n;i++) scanf("%d",&a[i].v);
//记录左右儿子
for(int i=1;i<=n;i++)
{
int x,y; scanf("%d %d",&x,&y);
a[i].s1=x;
a[i].s2=y;
}
for(int i=1;i<=n;i++)
{
int s1=a[i].s1;
int s2=a[i].s2;
if(s1>0&&s2>0&&a[s1].v==a[s2].v)//有左右儿子,并相等
{
f=1;
dfs(s1,s2);//判断是否对称
if(f==1) ans=max(ans,cnt(i));//是对称的,统计节点数量
}
}
printf("%d",ans);
return 0;
}