洛谷P5018 对称二叉树

时间:2020-04-17
本文章向大家介绍洛谷P5018 对称二叉树,主要包括洛谷P5018 对称二叉树使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

不多扯题目 直接题解= =

1.递归

由题目可以得知,子树既可以是根节点和叶节点组成,也可以是一个节点,题意中的对称二叉子树是必须由一个根节点一直到树的最底部所组成的树。

这样一来就简单了,我们很容易就能想到用递归的方法

1.枚举根节点,判断其左右两个孩子节点 是否存在 以及是否相等. 若存在并且点权相等,则一直递归左右两个孩子节点左右两个孩子节点 .

重复上述判断。

2.判断好对称二叉树后,就可以计算以该节点为根节点的对称二叉子树的节点数量并取最优值了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 1e6 + 10;//习惯性用定义法 当然也可以用const
int v[N], l[N], r[N];
//v[i]:节点i权值;l[i]:编号为i的节点的左孩子的编号;r[i]:编号为i的节点的右孩子的编号
int n,ans = 0;
bool pd; //判断是否为对称二叉子树
int cnt(int x) { //计算以x为根节点的对称二叉子树的节点数
  int sum 0;
  if (l[x]!=-1) sum+=cnt(l[x]);
  if (r[x]!=-1) sum+=cnt(r[x]);
  return sum+1; //算上根节点
}

void check(int x, int y) { //判断对称二叉子树
  if (x==-1&&y==-1) return ; //到底了 结束
  if (x==-1||y==-1||v[x]!=v[y]) { //不对称
    pd = false;
    return;
  }
  check(l[x], r[y]);
  check(r[x], l[y]); 
}

int main() {
 cin>>n;
  for (int i=1;i<=n;++i)
  cin>>v[i];
  for (int i=1;i<=n;++i)
  cin>>l[i]>>r[i];
  ans = 1; //至少有一个对称(一个节点)
  for(int i=1; i<=n;++i) {//枚举对称二叉子树的根节点
    if (l[i]!=-1&&r[i]!=-1&&v[l[i]]==v[r[i]]){
      pd=true; //先默认为是对称二叉子树
      check(l[i], r[i]);
      if (pd)
    ans=max(ans, cnt(i)); //如果是对称二叉子树就可以计算节点数取最大值了
    }
  }
cout<<ans;
  return 0;
}
check(l[x],r[y]); 
check(r[x],l[y]);

判断对称二叉子树时,应该是镜面对称的

所以在check时直接镜面对称即可

2dfs

如果一个二叉树是对称的,那么对于深度相同的两个节点u,v,必定有lson(u)lson(u)与rson(v)rson(v),rson(u)rson(u)与lson(v)lson(v),并且val_u=val_v:

int read()
{
int x=0,f=1;
char ch=getchar();
while('0'>ch||'9'<ch){
if (ch=='-')
f=-1;
ch=getchar();
}//判断正负
while('0'<=ch<='9'){
x=x*10+ch-48;
ch=getchar();
}//纯数字相加
return x*f;
}
int n,son[1000050][2],val[1000050],size[1000050];
//son[i][0]为i的左儿子
//son[i][1]为i的右儿子
void dfs(int u) //分别从左右扫一遍
{
size[u]=1;
if(son[u][0]!=-1)
{
dfs(son[u][0]);
size[u]+=size[son[u][0]];//size进入下一步dfs前先把当前状态改变
}
if (son[u][1]!=-1)
{
dfs(son[u][1]);
size[u]+=size[son[u][1]];
}
}

bool check(int u,int v)
{
if (u==-1&&v==-1)//特判
return true;
if (u!=-1&&v!=-1&&val[u]==val[v]&&check(son[u][0],son[v][1])&&check(son[u][1],son[v][0]))
return true;
return false;
}

int main()
{
n=read();
for (int i=1;i<=n;i++)
val[i]=read();
for (int i=1;i<=n;i++)
{
son[i][0]=read();
son[i][1]=read();
}
dfs(1);
int ans=0;
for (int i=1;i<=n;i++)
if(check(son[i][0],son[i][1]))
ans=max(ans,size[i]);
cout<<ans<<endl;
return 0;
}

然而我觉得这个近乎爆搜的打法还不如递归好使而且对我来说还挺难想= =

3.hash

可以直接hash树的形态,即分中序遍历1(先进左子树)和中序遍历2(先进右子树)记录hash值,对于每一个节点,若是此节点的左儿子的中序遍历1的hash值等于右儿子的中序遍历2的hash值,说明这个点为根的树是对称的(然而我用递归通过的= =所以hash就没打代码= =)

原文地址:https://www.cnblogs.com/SKTskyking/p/12721744.html