2019年蓝桥杯完全二叉树的权值

该博客介绍了一个关于完全二叉树的问题,即如何找到具有最大节点权值之和的深度。通过遍历节点并累加权值,同时跟踪当前深度和最大值,可以确定哪个深度的节点权值之和最大。代码实现中,博主使用了动态规划的方法,最终输出了具有最大和的最小深度。

完全二叉树的权值

题目描述

给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从 上到下、从左到右的顺序依次是 A1, A2, · · · AN,如下图所示:
在这里插入图片描述

现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点 权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。

注:根的深度是 1。

输入

第一行包含一个整数 N。 第二行包含N个整数A1,A2,··· AN。

对于所有评测用例,1≤ N ≤100000,−100000≤ Ai ≤100000。

输出

输出一个整数代表答案。

样例输入
7
1 6 5 4 3 2 1

样例输出
2

思路:

从头到尾一个一个加,每次加的结点数量到达二叉树每一深度的结点个数时,将结点个数归为0,二叉树下一深度的结点个数乘2,此时将更新每一层的最大值,注意最后还要比较一下计算的每一层的和与最大值相比较

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100010];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    int s=0,num=0,j=1,h=0,maxx=-99999999,maxh=0;
    for(int i=1; i<=n; i++)
    {
        s=s+a[i];//每一层结点的和
        num++;//记录加过结点的数量,控制它等于二叉树每一层的结点数量
        if(num==j) 
        {
            h++; //深度+1
            num=0; //从下一深度重新开始计数
            j=j*2; //下一深度的结点数量变为当前深度结点数量的2倍
            if(s>maxx) //更新每一层结点和的最大值
            {
                maxx=s;
                maxh=h;
            }
            s=0;//下一层计算和依然从0开始
        }

    }
    if(s>maxx)
       maxh=h+1; //举个例子吧,当第三层的和此时为最大值,第四层的和小于第三层,不进入更新最大值,但此时第五层的结点和大于第四层但是第五层的结点没有满(不是满二叉树),需要在最后深度+1
    printf("%d\n",maxh);
    return 0;
}
### 蓝桥杯 完全二叉树 权值 Java 实现 解题思路 #### 问题分析 完全二叉树是一种特殊的二叉树结构,其特点是除了最后一层外,其他各层节点数都达到最大值,并且最后一层的节点全部靠左排列。对于本题而言,给一棵包含 \(N\) 个节点完全二叉树每个节点一个权值 \(A_i\),目标是从根节点到叶子节点的所有路径中找到一条路径使得该路径上的节点权值之和最大。 此问题可以通过模拟完全二叉树的层次关系来解决。由于题目已经给出了节点编号按照从上到下、从左到右的顺序依次为 \(A_1, A_2, \dots, A_N\) 的特点,因此可以利用数组存储这些节点并计算每条可能路径的最大权值和[^1]。 --- #### 数据结构设计 为了高效处理完全二叉树中的父子节点关系,可以直接通过数组索引来表示父节点与子节点的关系: - 如果某个节点的索引为 \(i\)(基于 1-based 编号),那么它的左孩子节点索引为 \(2i\),右孩子节点索引为 \(2i+1\)。 - 对于任意一层 \(k\),这一层的第一个节点索引为 \(2^{(k-1)}\),最后一个节点索引为 \(2^k - 1\)。 这种性质允许我们无需显式构建二叉树对象,而是直接操作一维数组完成所有逻辑运算[^4]。 --- #### 动态规划求解方法 义状态转移方程用于记录到达当前节点时的最大路径权重总和: \[ dp[i] = A[i] + \max(dp[\text{parent}(i)], 0) \] 其中, - \(dp[i]\): 表示从根节点到第 \(i\) 个节点的最大路径权值; - \(\text{parent}(i)\): 是指第 \(i\) 个节点的父亲节点索引,可通过公式 \((\lfloor i/2 \rfloor)\) 计算得出。 最终结果即为所有叶节点对应的 \(dp[i]\) 值中的最大者。注意这里需要特别考虑负权值的情况——如果某条路径累积权值小于零,则可以选择放弃这条路径继续向下延伸[^3]。 以下是完整的算法流程描述: 1. 初始化动态规划表 `dp` 数组大小等于输入序列长度 \(N\) 并赋初值均为零。 2. 将第一个元素单独初始化为其自身的数值作为起点条件 (\(dp[1]=A[1]\))。 3. 遍历整个数组更新每一个非根节点处的状态依据上述递推表达式逐步填充剩余部分直至结束位置。 4. 找到最后一批有效叶子结点集合里对应的最大累计得分返回作答即可。 --- #### 示例代码实现 (Java) ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); // 输入节点数量 long[] a = new long[n + 1]; // 存储节点权值 for(int i=1;i<=n;i++) { a[i] = sc.nextLong(); } long[] dp = new long[n + 1]; dp[1] = a[1]; // 初始状态设置 for(int i=2; i<=n; ++i){ int parentIndex = i / 2; dp[i] = Math.max(dp[parentIndex], 0L) + a[i]; } // 寻找所有叶子节点的最大值 long maxSum = Long.MIN_VALUE; for(int i=n;;--i){ if(i*2>n && i*2-n<2){ maxSum=Math.max(maxSum, dp[i]); }else{ break; } } System.out.println(maxSum); // 输出结果 } } ``` --- #### 复杂度分析 时间复杂度主要由两重循环决:一次读取数据填入数组以及后续逐一遍历更新 DP 表格的过程均只需线性扫描 O(N),故总体效率较高适合大规模测试案例运行需求。 空间复杂度方面仅需额外开辟两个辅助数组分别保存原始数据副本及其关联最优决策信息同样维持在线性范围内 O(N)[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值