Luogu P5018 对称二叉树 题解

前言

date:2019-11-15 CSP1 前一天

作为一个去年还是个稚嫩的选手参加NOIP2018的OIer,感到自己仿佛经历了一次时代大变革,心中感慨万分。

那是无知、迷茫的心情在考场上作答。知道今天打开这个题目,我才发现曾经的自己是多么氺,连这道题都没有拿全分。

(后来回忆起当时连搜索都勉勉强强,也算是情理之中吧)

题目

一棵有点权的有根树如果满足以下条件,则被轩轩称为对称二叉树:

  1. 二叉树;
  2. 将这棵树所有节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。

下图中节点内的数字为权值,节点外的 id 表示节点编号。

现在给出一棵二叉树,希望你找出它的一棵子树,该子树为对称二叉树,且节点数 最多。请输出这棵子树的节点数。

注意:只有树根的树也是对称二叉树。本题中约定,以节点 T 为子树根的一棵“子 树”指的是:节点T 和它的全部后代节点构成的二叉树。

输入格式

第一行一个正整数 n,表示给定的树的节点的数目,规定节点编号 1n,其中节点 11 是树根。

第二行 n 个正整数,用一个空格分隔,第 i 个正整数 vi 代表节点i 的权值。

接下来 n 行,每行两个正整数 li, ri,分别表示节点 i 的左右孩子的编号。如果不存在左 / 右孩子,则以 1 表示。两个数之间用一个空格隔开。

输出格式

输出文件共一行,包含一个整数,表示给定的树的最大对称二叉子树的节点数。

分析

1. 怎样去构建一棵二叉树:

(这还用说?)递归DFS

  1每一个节点设参数l,r表示它的左右孩子节点的编号;

  2每一个节点设参数size表示它的子节点个数(包括自己);

  3每一个节点设参数val表示它的权值

其中,1、3可以在输入中完成,2可以通过递归完成(递归处理之后统计结果)

2. 怎样判断一棵子树是不是“对称二叉树”:

  1若两个儿子节点均不存在,则当前是对称二叉树;

  2若有且只有一个儿子节点存在,则当前不是对称二叉树;

  3若两个儿子节点存在但权值不一致,则当前不是对称二叉树;

  4若两个儿子节点存在且权值一致,则进一步检查左儿子的左儿子和右儿子的右儿子是否对称,左儿子的右儿子和右儿子的左儿子是否对称,若都对称则当前是对称二  叉树,否则就不是。(递归下去)

3.怎样处理答案:

当这棵子树是“对称二叉树”的时候,我们更新答案为其与当前节点的size的最大值(顺势而为)

细节

1.一定要把每一个节点的size赋值为1

2.一定注意叶子节点是“对称二叉树”

3.一定不要用scanf(至于原因我也不知道,只是因为我提交的时候用scanf又是Wrong Answer 又是 Memory Limited Errow,改成cin之后就AC了)

4.一定要把答案的初始值赋为1(一棵二叉树总会有叶子节点)

代码

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n,res=1;//赋值
struct node//节点结构体
{
    int l,r,size,val;
}a[1000005];
inline bool judge(int lef,int rig)//判断一当前节点为根节点的子树是否为“对称二叉树”
{
    if(lef==-1 and rig==-1)//叶子节点
        return 1;
    if(lef==-1 or rig==-1)//独生子女
        return 0;
    if(a[lef].val^a[rig].val)//左右孩子权值不相等
        return 0;
    return judge(a[lef].l,a[rig].r)&judge(a[lef].r,a[rig].l);//递归检查
}
inline void dfs(int k)
{
    if(a[k].l^-1)//向左建树
    {
        dfs(a[k].l);
        a[k].size+=a[a[k].l].size;
    }
    if(a[k].r^-1)//向右建树
    {
        dfs(a[k].r);
        a[k].size+=a[a[k].r].size;
    }
    if(judge(a[k].l,a[k].r))
        res=max(res,a[k].size);//更新答案
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(register int i=1;i<=n;i++)
        cin>>a[i].val,a[i].size=1;
    for(register int i=1;i<=n;i++)
        cin>>a[i].l>>a[i].r;
    dfs(1);//建树兼更新答案
    cout<<res<<endl;
    return 0;
}

总结

考前最后一天,祝所有OIer RP++,AK全场!

猜你喜欢

转载自www.cnblogs.com/chengyurui/p/11865463.html