当前位置:   article > 正文

信息学奥赛一本通 1981:【18NOIP普及组】对称二叉树 | 洛谷 P5018【NOIP2018 普及组】 对称二叉树_p5018 [noip2018 普及组] 对称二叉树

p5018 [noip2018 普及组] 对称二叉树

【题目链接】

ybt 1981:【18NOIP普及组】对称二叉树
洛谷 P5018【NOIP2018 普及组】 对称二叉树

【题目考点】

  1. 二叉树

【解题思路】

  1. 先求出二叉树中各子树的结点数
  2. 遍历二叉树,判断每个子树是否是对称二叉树
  • 判断一个二叉树是否是对称二叉树:
  • 对称变换:将该树中所有结点的左右子树交换。显然,一棵树经过两次对称变换后,会变为原来的树。
  • 两树对称:如果树1经过对称变换可以变为树2,那么称树1与树2对称。显然,树1与树2对称时,树2与树1对称。
  • 如果一个二叉树是对称二叉树,那么其左子树应该与右子树对称。
    • 证明:二叉树是对称的,那么其经过对称变换后的左子树,是由原右子树变换过来的。已知对称变换后的树与原树相同,那么变换后的左子树与原左子树相同,那么原左子树与原右子树是对称的。
  • 设函数check(),参数为树1、树2两棵树的根,该函数判断树1、树2是否对称。
  • 判断两棵树是否对称:
    • 如果两棵树都是空树(根结点地址都为-1),那么它们是对称的。
    • 如果两棵树都不是空树,同时满足如下条件时,二者才是对称的
      • 两棵树根结点的权值应该相同
      • 两棵树的结点数应该相同
      • 树1的左子树应该与树2右子树对称。
      • 树1的右子树应该与树2的左子树对称

【题解代码】

解法1:
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
typedef struct Node
{
    int val, left, right;//val:权值, left:左孩子地址 right:右孩子地址
}Node;
Node tree[N];//tree[i],为id为i的结点
int treeNodeNum[N];//treeNodeNum[i]保存id为i的结点的子树的结点数。
int n;
int mxNodeNum;//结点数量最大的对称子树的结点数

//判断以root1为根的子树和以root2为根的子树是否对称
bool check(int root1, int root2)
{
    if(root1 == -1 && root2 == -1)//空结点,相同
        return true;
    else if(root1 != -1 && root2 != -1 && //左右子树都有结点
            tree[root1].val == tree[root2].val && //树根结点权相同,
            treeNodeNum[root1] == treeNodeNum[root2] && //树结点数相同
            check(tree[root1].left, tree[root2].right) && //经过对称变换后,root2树的右子树应该与root1树的左子树对称
            check(tree[root1].right, tree[root2].left))//经过对称变换后,root2树的左子树应该与root1树的右子树对称
        return true;
    else
        return false;
}

//获取树的结点数
int getNodeNum(int root)
{
    if(root == -1)
        return 0;
    else
    {
        int nodeNum = getNodeNum(tree[root].left) + getNodeNum(tree[root].right) + 1;
        treeNodeNum[root] = nodeNum;
        return nodeNum;
    }
}

//确定结点最多的对称的子树的结点数
void Search(int root)
{
    if(root != -1)
    {
        if(treeNodeNum[root] <= mxNodeNum)//剪枝,如果当前子树的结点数已经比获得的最大对称子树结点数要小,那么没必要再搜索下去。
            return;
        if(check(tree[root].left, tree[root].right))//如果树root是对称的,那么其左右子树对称
            mxNodeNum = treeNodeNum[root];//如果对称,记录结点数。由于已有剪枝操作,此时treeNodeNum[root]一定大于mxNodeNum
        else
        {
            Search(tree[root].left);
            Search(tree[root].right);
        }
    }
}

int main()
{
    scanf("%d\n", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &tree[i].val);
    for(int i = 1; i <= n; ++i)
        scanf("%d %d", &tree[i].left, &tree[i].right);
    getNodeNum(1);//初始化树的各子树结点数
    Search(1);//从根结点开始,遍历所有子树,找出对称子树,并看其结点数,保存最大结点数
    printf("%d", mxNodeNum);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/731903
推荐阅读
相关标签
  

闽ICP备14008679号