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

在考场上的玄学思路:

 

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

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

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

什么意思呢?

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

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

同理,判断时也取反

分四种情况:

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

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

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

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

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

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值