luogu5018:对称二叉树:noip2018普及组T4

题目连接

  • 该题是luogu试炼场的2-14:T4

题目大意

  1. 给出一棵树;
  2. 求最大的对称子树的规模

题目分析

  • 对称树:以某个节点为根,一直延伸到叶子,完全对称
  • 我的读题最大误解,因为下面的样例:

在这里插入图片描述
上图的样例给了我一个极大的误导,以为是蓝色框和绿色框两个子树对称,所以“对称子树的单边值”是3。

  • 正解应该是下图:
    在这里插入图片描述
    上图红框中的子树内部对称,所以对称的子树节点总数是3。


解题思路:

  1. 扫描所有n个节点,深搜比较他们的左右儿子(类似建堆的思维);
  2. 如下图:对于当前父节点 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;
}


猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/90021429