1.原题和原题链接

原题链接

P15801 [GESP202603 六级] 完全二叉树

题目描述

给定一棵包含 n n n 个结点的有根二叉树,结点依次以 1 , 2 , … , n 1,2,\dots,n 1,2,,n 编号,根结点编号为 1 1 1

对于结点 i i i,其左儿子的编号记为 l i l_i li,右儿子编号记为 r i r_i ri。特别地,如果左儿子不存在则 l i = 0 l_i=0 li=0,如果右儿子不存在则 r i = 0 r_i=0 ri=0

树中每个结点都对应一棵以其为根的子树。请你求出给定有根树的所有 n n n 棵子树中,有多少棵子树是完全二叉树。

输入格式

第一行,一个正整数 n n n,表示有根二叉树结点数量。

接下来 n n n 行,每行两个正整数 l i , r i l_i,r_i li,ri,表示结点 i i i 的左儿子编号和右儿子编号。

输出格式

输出一行,一个整数,表示所有子树中完全二叉树的数量。

输入输出样例 #1

输入 #1

4
2 3
4 0
0 0
0 0

输出 #1

4

输入输出样例 #2

输入 #2

4
2 3
0 0
4 0
0 0

输出 #2

3

说明/提示

对于 40 % 40\% 40% 的测试点,保证 1 ≤ n ≤ 500 1\leq n\leq 500 1n500

对于所有测试点,保证 1 ≤ n ≤ 10 5 1\leq n\leq 10^5 1n105

2.主要思路

这道题让我们找所有子树里完全二叉树的数量,我们用DFS遍历每个节点就行。首先得明白完全二叉树的特点:要么是满二叉树,要么最后一层左边全满、右边缺几个。所以给每个节点存两个状态,h[u]是子树高度,dp[u]标记子树类型:2代表满二叉树,1代表非满的完全二叉树,0不是完全二叉树。DFS的时候先递归左右孩子,再判断当前节点:叶子节点肯定是满二叉树;只有左孩子且左孩子是满二叉树,那当前是完全二叉树;左右孩子高度相同,得都是满二叉树或者左满右完全;左孩子比右高一层,得左是完全二叉树且右是满二叉树。每符合条件就计数加1,最后输出总数就行。

3.AC代码

#include<bits/stdc++.h>
using namespace std;
#define N 100005
struct node {
    int l, r;
};
node a[N];
int dp[N], h[N];
int ans;
void dfs(int u, int depth) {
    h[u] = depth;
    if (a[u].l > 0) {
        dfs(a[u].l, depth + 1);
        h[u] = max(h[u], h[a[u].l]);
    }
    if (a[u].r > 0) {
        dfs(a[u].r, depth + 1);
        h[u] = max(h[u], h[a[u].r]);
    }
    if (a[u].l == 0 && a[u].r == 0) dp[u] = 2;
    else if (a[u].r == 0 && h[a[u].l] == depth + 1) dp[u] = 1;
    else if (h[a[u].l] == h[a[u].r]) {
        if (dp[a[u].l] == 2 && dp[a[u].r] == 2) dp[u] = 2;
    	else if (dp[a[u].l] == 2 && dp[a[u].r] == 1) dp[u] = 1;
    }
    else if (h[a[u].l] == h[a[u].r] + 1) {
        if ((dp[a[u].l] == 1 || dp[a[u].l] == 2) && dp[a[u].r] == 2) dp[u] = 1;
    }
    ans += (dp[u] > 0);
}
int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].l >> a[i].r;
    }
    dfs(1,0);
    cout << ans;
    return 0;
}

以上就是本篇全部内容,感谢浏览!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐