【题解】【NOIP2018PJ】对称二叉树

本文介绍一种高效判断二叉树是否对称的算法,通过对比左右子树的结构和节点值,结合节点数量优化,实现快速准确的对称性判断。代码使用C++实现,包含深度优先搜索和对称性验证逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在考场上的玄学思路:

 

这道题的思路相对来说还是很好想出来的(

首先,对于每一个节点,只要右儿子节点与左儿子节点的权值不同,就肯定不是对称的,舍去

然后,每一次向下走一层的时候,左子树跟右子树的路径取反

什么意思呢?

就是,你左子树向右走,右子树就向左走;左子树向左走,右子树向右走

(如果这里不能理解建议动手画图看一下)

同理,判断时也取反

分四种情况:

  • 如果左子树的根节点没有左子树而右子树的根节点有右子树,那么结构上肯定不满足对称性,舍去

  • 如果左子树的根节点没有右子树而右子树的根节点有左子树,那么结构上肯定不满足对称性,舍去

  • 如果左子树的根节点有左子树而右子树的根节点没有右子树,那么结构上肯定不满足对称性,舍去

  • 如果左子树的根节点有右子树而右子树的根节点没有左子树,那么结构上肯定不满足对称性,舍去

那么什么时候满足对称性呢?

——当搜索到两个节点,两个节点同为叶子结点且权值相等时

但只要有其中某一条路径不满足,整颗子树肯定不满足

那么,按照以上思路打出来的代码是多少分的呢?我怎么知道

96分

用了一次下载数据的机会……(in luogu)

哦,炸了,极限数据卡成一条链了……

那么,我们还可以加上什么优化呢?

给大家3分钟的思考时间……


 

优化很简单——只要左右子树的节点数目不同,则结构肯定不对称!

那么这个优化加上去多少分?

当然AC啦!

上代码!喂喂喂音乐老师怎么回事BGM呢

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct note
{
    int left;
    int right;
    int val;
};

int n,ans;
note a[1000010];
int d[1000010];

int fast_read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        {
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int dfs(int root)
{
    //printf("%d\n",root);
    if(a[root].left==-1&&a[root].right==-1)
    {
        return 1;
    }
    int s=1;
    if(a[root].left!=-1)
    {
        s+=dfs(a[root].left);
    }
    if(a[root].right!=-1)
    {
        s+=dfs(a[root].right);
    }
    d[root]=s;
    return s;
}

bool dfs2(int left,int right)
{
    if(a[left].val!=a[right].val)
    {
        return 0;
    }
    if(a[left].left==-1)
    {
        if(a[right].right!=-1)
        {
            return 0;
        }
    }
    if(a[left].right!=-1)
    {
        if(a[right].left==-1)
        {
            return 0;
        }
    }
    if(a[left].left!=-1)
    {
        if(a[right].right==-1)
        {
            return 0;
        }
    }
    if(a[left].right==-1)
    {
        if(a[right].left!=-1)
        {
            return 0;
        }
    }
    if(a[left].right==-1&&a[left].left==-1)
    {
        return 1;
    }
    bool f=1;
    if(!dfs2(a[left].left,a[right].right))
    {
        f=0;
    }
    if(!dfs2(a[left].right,a[right].left))
    {
        f=0;
    }
    return f;
}

void work()
{
    for(int i=1;i<=n;i++)
    {
        if(a[i].left!=-1&&a[i].right!=-1)
        {
            if(d[i]>ans&&d[a[i].left]==d[a[i].right]&&dfs2(a[i].left,a[i].right))
            {
                ans=d[i];
            }
        }
        else
        {
            ans=max(ans,1);
        }
        //printf("%d\n",ans);
    }
}

int main()
{
    //freopen("testdata (2).in","r",stdin);
    n=fast_read();
    for(int i=1;i<=n;i++)
    {
        a[i].val=fast_read();
        d[i]=1;
    }
    for(int i=1;i<=n;i++)
    {
        a[i].left=fast_read();
        a[i].right=fast_read();
    }
    int k=dfs(1);
    work();
    /*
    for(int i=1;i<=n;i++)
    {
        printf("%d\n",d[i]);
    }
    */
    printf("%d\n",ans);
    return 0;
}

各位,暴力出奇迹啊!

转载于:https://www.cnblogs.com/tt66ea-blog/p/10057803.html

NOIP 2018 普及组初赛第1028题的题解如下: 题目描述: 给定一个正整数N,要求编写一个程序,计算出它的阶乘N!。阶乘N!是所有小于或等于N的正整数的乘积,且0!定义为1。例如:5! = 5 × 4 × 3 × 2 × 1 = 120。 输入描述: 输入仅包含一个正整数N,其范围为1到20。 输出描述: 输出为计算得到的阶乘N!的值。 解题思路: 1. 使用一个数组来存储中间计算结果。 2. 从1开始,依次计算到N的所有整数的阶乘。 3. 每计算出一个数的阶乘,就将其乘到数组中,更新数组的值。 4. 最终数组存储的就是N!的结果。 注意点: - 由于N的范围为1到20,而20!的结果是一个非常大的数,普通的数据类型无法存储,因此需要使用数组来模拟大数运算。 - 在实现大数乘法时,需要注意进位的问题。 以下是一个简化的伪代码示例: ``` 输入:N 创建一个足够大的数组result用于存储结果 result[0] = 1 // 初始化结果为1 对于i从1到N: carry = 0 // 进位初始化为0 对于j从0到result的长度减1: temp = result[j] * i + carry result[j] = temp % 10 // 更新当前位的值 carry = temp / 10 // 计算新的进位 结束循环 如果carry不为0,则继续添加进位 结束循环 输出result数组(从后往前输出,以得到正确的顺序) ``` 实际编程时,需要注意数组的索引处理和进位处理,以及在输出时避免在前面输出不必要的零。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值