P1087 [NOIP2004 普及组] FBI 树

该篇文章介绍了如何使用C++定义一个表示字符串树结构的节点类,实现从输入字符串中构建树结构,并通过后序遍历算法检查字符串的独特性,输出B或I字符。
摘要由CSDN通过智能技术生成

#include<bits/stdc++.h>
using namespace std;
struct node{//定义节点 
    int num;//赋的值 
    string str;//所在的串 
    int father_num;//父节点 
    int sonl=0,sonr=0,visit;//sonl:左孩子,sonr:右孩子,visit:判断输没输出,用于后序遍历函数 
}n [2048];//已经讲过2048的来历啦!
int t=1;//所赋的值的变量,说实话也就是给每个点标的号 
string a;//输入的字符串 
void gou_zao_shu(int from/*字符串起始点*/,int to/*字符串截止点*/,int l/*从哪里来(所谓的父节点)*/,int pds/*判断是父节点的左或右孩子*/){
    n[t].num=t;//标号 
    n[t].father_num=l;//把l标记成父节点(因为1个点只有一个父节点) 
    string s;//本节点的字符串 
    for(int i=from;i<=to;i++){
        s+=a[i];//连接(+在这里是连接的意思) 
    }
    n[t].str=s;//存储字符串 
    if(pds==0){//来路是左孩子 
        n[l].sonl=n[t].num;//存为父节点的左孩子 
    }else{//来路是右孩子 
        n[l].sonr=n[t].num;//存为父节点的右孩子 
    }
    t++;//标记的值++
    if(from==to){//字符串长度为1(叶节点) 
        return;//免得死循环 
    }
    int root=t-1;//把此次设成根(叶节点已经return了,不用担心叶节点死循环) 
    gou_zao_shu(from,(from+to)/2,root,0);//已验证过开始和结束,搜索左孩子,标记父节点。
    gou_zao_shu((from+to)/2+1,to,root,1);//已验证过开始和结束,搜索左孩子,标记父节点。 
    return;//完美
}
void hou_xu_bian_li(int x){//后序遍历函数 注明一下:结构体visit其实并没有什么用,因为一个点只可能走一遍,但并不影响 
    if(n[x].num==0){//超出范围(想了想没太大用,但安全)  
        return;//拽回来 
    }
    if(n[x].sonl==0&&n[x].sonr==0){//叶节点(左右孩子均为0)     
        bool fbi=true;//输出判断的变量 
        for(int i=0;i<n[x].str.length();i++){//循环判断 
            if(n[x].str[i]!=n[x].str[0]){//与第一个不一样 
                fbi=false;//有重的说明有重复,记为false 
                cout<<"F";//混合输出F 
                break;//跳出循环 
            }
        } 
        if(fbi==true){//无重 
            if(n[x].str[0]=='1'){//第一个为1 
                cout<<"I";//输出I 
            }else{//第一个为0 
                cout<<"B";//输出B 
            }
        }
        n[x].visit=1;//标记已经处理过 
        return;//返回上一级 
    }
    hou_xu_bian_li(n[x].sonl);//后序左孩子 (先遍历左) 
    hou_xu_bian_li(n[x].sonr);//后序右孩子 (先遍历右) 
    if(n[n[x].sonl].visit==1&&n[n[x].sonr].visit==1){//左右孩子都被遍历 
        bool fbi=true;//和上面叶节点的做一样处理进行输出 
        for(int i=0;i<n[x].str.length();i++){//循环每个字符 
            if(n[x].str[i]!=n[x].str[0]){//不一样 
                fbi=false;//改值 
                cout<<"F";//输出混合的要求 
                break;//跳出循环 
            }
        }
        if(fbi==true){//无重 
            if(n[x].str[0]=='1'){//按照要求输出 
                cout<<"I";
            }else{
                cout<<"B";
            }
        }
        n[x].visit=1;//标记 
        return;//返回 
    }
    return;//更安全 
}
int main(){//终于到主函数了! 
    int nothing;//我认为给2^n无用 
    scanf("%d",&nothing);//把这个无用的玩意输入进来 
    cin>>a;//输入字符串 
    if(a.length()==1){//长度为1,注意!有点卡这这里! 
        if(a=="0"){//为0 
            cout<<"B";//输出B 
        }else{//为1 
            cout<<"I";//输出I 
        } 
        return 0;
    }
    //进行正常处理
    //进行根节点处理 
    n[t].num=1;//整个串标为1,根节点 
    n[t].father_num=0;//无父节点 
    n[t].str=a;//储存字符串 
    t++;//把标记的变量++ 
    //构造字符串树 
    gou_zao_shu(0,a.length()/2-1,1,0);//构造树(左孩子们)
    gou_zao_shu((a.length()+1)/2,a.length()-1,1,1);//构造树(右孩子们) 
    //下面开始遍历
    n[0].visit=1;//设置范围,避免越界 
    n[0].str="3";//设置,更保险 
    hou_xu_bian_li(1);//后序遍历 
    return 0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值