P1087 [NOIP 2004 普及组] FBI 树

题解:洛谷 P1087 [NOIP 2004 普及组] FBI 树 等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。包含一行,这一行只包含一个字符串,即。树是一种二叉树,它的结点类型也包括。串,请用上述构造方法构造出一棵。树,并输出它的后序遍历序列。组成的字符串分为三类:全。#普及-# #DFS-一维#本文分享的必刷题目是从。 阅读详情

记录143

#include<bits/stdc++.h>
using namespace std; // 使用标准命名空间std

string s; // 存储01字符串

// 递归函数:处理字符串区间 [l, r]
void dfs(int l,int r) {
    // 1. 判断当前区间的类型
    bool has0=false,has1=false;
    for(int i=l;i<=r;i++) {
        if(s[i]=='0') has0=true;
        else has1=true;
    }
    
    char type; // 当前节点的类型
    if(has0&&has1) type='F'; // 既有0又有1
    else if(has0) type='B';    // 只有0
    else type='I';             // 只有1

    // 2. 如果区间长度大于1,继续递归切分左右子树
    if(l<r) {
        int mid=(l+r)/2;
        dfs(l,mid);       // 递归左子树
        dfs(mid+1,r);   // 递归右子树
    }

    // 3. 后序遍历:最后输出当前节点的类型
    cout<<type;
}

int main() { // 主函数入口
    ios::sync_with_stdio(false); // 关闭同步,加速IO
    cin.tie(0);
    
    int n;
    cin>>n>>s; // 读入N和01串
    
    // 启动递归,初始区间是整个字符串 [0, s.size()-1]
    dfs(0,s.size()-1);
    
    cout<<"\n"; // 输出换行
    return 0;
}

    题目传送门https://www.luogu.com.cn/problem/P1087


    前言

    我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

    • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的优快云账号,我会持续更新高质量算法解析。
    • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
    • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

    核心解题思路

    这道题是一道非常经典的递归分治与二叉树遍历问题。

    1. 核心原理:
      题目给出了 FBI 树的递归构造方法:根节点的类型由当前字符串决定,如果字符串长度大于 1,则从中间一分为二,分别构造左子树和右子树。这天然契合二叉树的结构。题目要求输出后序遍历序列,即“左子树 -> 右子树 -> 根节点”的顺序。

    2. 算法设计(分治递归):
      我们不需要真正地在内存中构建出树的结构(即不需要定义节点类或结构体)。只需要写一个递归函数,传入当前处理的字符串区间 [l, r]。在函数内部,先判断当前区间对应的节点类型,然后如果区间长度大于 1,就递归处理左半区间和右半区间,最后输出当前节点的类型。这种“先递归左右,再输出自身”的操作,恰好就是后序遍历。


     代码分块详细解释

    1. 头文件与全局变量定义

    #include<bits/stdc++.h>
    using namespace std; // 使用标准命名空间std
    string s; // 存储01字符串
    • 详细分析:题目中字符串的长度为 2N2N ,当 N=10N=10 时,字符串长度最多为 210=1024210=1024 。使用 string 类型存储非常方便,且可以像数组一样通过下标访问。将字符串定义为全局变量,可以避免在递归函数中反复传递字符串,提高运行效率。

    2. 核心逻辑:分治递归函数(dfs)

    // 递归函数:处理字符串区间 [l, r]
    void dfs(int l, int r) {
        // 1. 判断当前区间的类型
        bool has0=false, has1=false;
        for(int i=l; i<=r; i++) {
            if(s[i]=='0') has0=true;
            else has1=true;
        }
        
        char type; // 当前节点的类型
        if(has0 && has1) type='F'; // 既有0又有1
        else if(has0) type='B';    // 只有0
        else type='I';             // 只有1
    
        // 2. 如果区间长度大于1,继续递归切分左右子树
        if(l < r) {
            int mid = (l+r)/2;
            dfs(l, mid);       // 递归左子树
            dfs(mid+1, r);     // 递归右子树
        }
    
        // 3. 后序遍历:最后输出当前节点的类型
        cout << type;
    }
    • 详细分析:这是本题的灵魂所在,完美体现了“分治”与“后序遍历”的结合。
      • 节点类型判定:通过一个 for 循环遍历当前区间 [l, r] 内的所有字符,用两个布尔变量 has0 和 has1 记录是否出现过 0 和 1。根据两者的组合情况,确定当前节点是 'F'、'B' 还是 'I'。
      • 递归切分:如果 l < r,说明当前区间长度大于 1,需要继续向下构造子树。计算中间位置 mid = (l+r)/2,然后分别对左半区间 [l, mid] 和右半区间 [mid+1, r] 发起递归调用。
      • 后序输出:注意代码的执行顺序是先调用 dfs(l, mid)(处理左子树),再调用 dfs(mid+1, r)(处理右子树),最后才执行 cout << type(输出根节点)。这严格遵循了后序遍历“左右根”的规则,保证了最终拼接出的字符串就是正确的后序遍历序列。

    3. 主函数:输入处理与启动递归

    int main() { 
        ios::sync_with_stdio(false); // 关闭同步,加速IO
        cin.tie(0);
        
        int n;
        cin >> n >> s; // 读入N和01串
        
        // 启动递归,初始区间是整个字符串 [0, s.size()-1]
        dfs(0, s.size()-1);
        
        cout << "\n"; // 输出换行
        return 0;
    }
    • 详细分析:主函数负责读取输入的 NN 和 01 串,并启动递归。dfs(0, s.size()-1) 表示最初我们要处理的是整个字符串,左右边界分别是 0 和 字符串长度-1。

    核心逻辑总结表

    代码模块核心变量/操作精炼作用解决的痛点
    节点类型判定has0 与 has1 布尔标记遍历当前区间,判断包含的字符种类准确确定当前递归层对应的节点是 F、B 还是 I
    递归切分int mid = (l+r)/2将当前区间从正中间一分为二完美契合 FBI 树“等长左右子串”的构造规则
    递归左子树dfs(l, mid)递归处理左半部分区间深入树的左侧分支,遵循后序遍历“先左”的规则
    递归右子树dfs(mid+1, r)递归处理右半部分区间深入树的右侧分支,遵循后序遍历“后右”的规则
    根节点输出cout << type在左右子树递归结束后输出当前类型遵循后序遍历“最后根”的规则,直接拼接出最终答案
    递归终止if(l < r)当区间长度为1时不再向下递归保证了递归在叶子节点处正确停止,防止死循环
    题解:P1087 [NOIP 2004 普及组] FBI 树 题目其实很简单,直接按照题意递归模拟就完事了。 阅读详情

    相关推荐

    为什么BGA焊点总在四个角先坏?一次热-振耦合仿真给你讲明白

    本文通过Ansys Workbench进行热-振耦合仿真,深入分析了BGA焊点在四个角点先失效的机理。研究发现,角点焊点由于CTE失配、振动载荷放大及几何应力集中等因素,承受的等效塑性应变和动态应力显著高于中心区域,导致其疲劳寿命大幅降低。仿真数据揭示了角点焊点的应力分布和蠕变特性,为电子封装可靠性设计提供了重要依据。

    weixin_42535461的博客 439

    洛谷 P1087 [NOIP2004 普及组] FBI 树

    本文介绍了洛谷P1087题目的解题思路,要求根据给定的01字符串构建FBI树并输出后序遍历结果。FBI树的节点分为F、B、I三类,分别对应字符串含0和1、全0、全1的情况。通过递归方法将字符串不断平分构建二叉树,并在递归过程中判断节点类型。后序遍历顺序处理左右子树后再输出当前节点类型。文章提供了C++和Python的实现代码,并指出题目关键在于理解题意和递归处理,整体难度较低。

    jzwalliser的博客 1655

    ADS(Arm Developer Suite)安装的坑!

    实验课老师让我们区安装ADS,作为嵌入式开发的工具,原本以为这只是一个简单的软件,但是当我安装的时候,我才发现这软件太难了!安装了我大半天,看了其他的博客之后,最终才安装成功???????? 安装过程的一个巨坑就是:安装路径!以及安装许可注册文件 如果没有注意路径,最后安装成功以后打开软件就是蜜汁报错???? 报错了怎么办?删掉已安装的东西,重新安装吧,而且要删干净 再次安装的时候,打开安装包是这个提示...

    weixin_42795819的博客 8220

    P1087 [NOIP2004 普及组] FBI 树

    大家好!下面为大家讲解我做了两年半的题目,

    Aa12345678bbb的博客 831

    本地部署gradle

    在部署CAS构建执行包时,如果按照CAS的官方命令gradlew clean build,如果系统没安装过gradle,这个步骤将会从网上下载gradle,但是进度非常慢,耗时很长。为了更快地完成项目构建,我们可以直接在本地部署好gradle,节省一点时间。

    益添的博客 780

    详述字符集与汉字编码

    字符集与字符编码是文本处理的基础概念。字符集定义字符集合(如ASCII、GB2312、Unicode),字符编码则规定字符如何存储为二进制数据。汉字编码经历了从区域化(GB2312、GBK、BIG5)到全球化(Unicode)的演进,Unicode通过UTF-8、UTF-16等编码方案实现跨语言兼容。UTF-8因兼容ASCII、节省空间且无乱码风险,成为中文互联网的主流编码。正确处理编码问题需统一标准、明确声明格式,并注意生僻字的特殊处理。

    零零发不爱ai的博客 806

    【题解】【洛谷P1087】【树形数据结构,递归】—— [NOIP2004 普及组] FBI 树

    平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。

    Pantheraonca的博客 1477

    技术面 - 手撕算法题整理

    这篇博客整理了华为OD面试中涉及的算法题,包括LeetCode热门题目、OD原题和需要手写的算法,如二分查找、冒泡排序等。建议优先刷"hot100"的LeetCode题目,全刷OD原题,以及掌握手撕算法的基本原理。

    m0_73659489的博客 1025

    洛谷 P1087 [NOIP 2004 普及组] FBI 树

    FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。现在给定一个长度为 2N 的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。一个字符串,即 FBI 树的后序遍历序列。第二行是一个长度为 2N 的 01 串。第一行是一个整数 N(0≤N≤10),noip2004普及组第3题。对于全部的数据,N≤10。

    2401_87918203的博客 318

    【深度学习新浪潮】李飞飞团队VAGEN框架深度解析:让VLM智能体学会“三思而后行“

    VAGEN框架的真正价值,不仅在于性能指标的突破,更在于重新定义了VLM智能体的发展方向——人工智能的进步不应只追求"做得对",更要实现"想得清"。李飞飞团队通过强制显式思考、动态表示适配和精细化奖励三大创新,让智能体第一次具备了可解释的世界建模能力。正如人类通过"观察-预测-行动"认识世界,VAGEN为AI注入的这种思考范式,或许正是通往通用人工智能的关键一步。对于开发者而言,开源的VAGEN框架不仅提供了强大的工具,更揭示了一个重要理念:让AI学会思考,比让它学会执行更重要。

    专注:太空算力、AI infra、异构调度、大模型成本工程 281

    Statistics and Machine Learning Toolbox

    Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

    打卡信奥刷题(098)用C++信奥P1087[普及组/提高][NOIP2004 普及组] FBI 树

    我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为2N的 01 串S可以构造出一棵 FBI 树TTRSS1SS1​S2​S1​RT1​S2​RT2​现在给定一个长度为2N的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。

    Loge谈信奥--一个专注于信奥人的博客 1986

    VC中sqlite的使用

    在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

    洛谷P1087 [NOIP2004 普及组] FBI 树c语言

    洛谷P1087 [NOIP2004 普及组] FBI 树 二叉树的后序遍历 文章目录思想代码 思想 [1] 二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。   [2] 后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。 注释:本题就是用到了二叉树。解题时思路清晰、目的明确就好了,主要分以下几个步骤: 1、以字符串的形式录入原始串s; 2、按题

    weixin_61966129的博客 1744

    汉书HE8,好用的汇编代码编写工具

    汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

    jdk-8u144-linux-x64.tar.gz.

    该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

    P1087 [NOIP2004 普及组第三题] FBI 树

    FBI树是一种二叉树,它的结点类型包括F结点,B结点和I结点三种。

    hnjzsyjyj的专栏 1057

    P1087 [NOIP2004 普及组] FBI 树(算法1-4.1)

    【代码】P1087 [NOIP2004 普及组] FBI 树(算法1-4.1)

    2301_81394465的博客 166

    两种做法 P1087 [NOIP2004 普及组] FBI 树 队列和递归

    我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为 B 串,全“1”串称为 I 串,既含“0”又含“1”的串则称为 F 串。 FBI 树是一棵二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为 2N 的“01”串 S 可以构造出一棵 FBI 树 T,递归的构造方法如下: (1) T 的根结点为 R,其类型与串 S 的类型相同; (2) 若串 S 的长度大于 1,可将串 S 从中间分开,分为等长的左右子串 S1 和 S2;由左子串 S1 构造 R 的左子树 T1,由右子串

    qq_44343213的博客 783
    上一篇: P1827 [USACO3.4] 美国血统 American Heritage
    下一篇: P1030 [NOIP 2001 普及组] 求先序排列
    谢天谢地AC了 | 信奥教练
    博客等级 码龄1年 53粉丝 177原创
    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    个

    红包个数最小为10个

    元

    红包金额最低5元

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

    抵扣说明:

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

    余额充值