zoukankan      html  css  js  c++  java
  • 【洛谷】普及区_树形数据结构(不全)

    简单说说二叉树。

    如图:

    二叉树的每个树节点都有两个子节点(通俗称作父子关系);

    节点A,他是B和C两个节点的爸爸,D节点可以说是他的孙子;

    节点B,没有儿子;

    节点C,只有一个左儿子D;

    节点D,没有儿子。

    聪明的你肯定发现:

    左儿子的序号等于父亲序号的2倍,右儿子的序号等于父亲序号的2倍+1;

    因此可以利用递归遍历整棵二叉树。

    P1087 FBI树

    本题对于二叉树新人来说难点是建树(比如我在课间想了一上午才明白)。

    (其实只要动动笔在纸上画一画就很清楚了)

    其次就是查询字符串的“FBI”值(弄一个判断函数)

    #include<cstdio>
    #include<iostream>
    #include<string>
    using namespace std;
    
    int N, count;
    string s;
    char FBI[10000];
    
    char find(string s){ // 查询
        int h = 0;
        bool one = true;
        for(int i = 0; i < s.size(); i++){
            if(h == 1 && s[i] == '0') one = false;
            if(h == -1 && s[i] == '1') one = false;
            if(s[i] == '1' && i == 0) h = 1;
            if(s[i] == '0' && i == 0) h = -1;
        }
        if(one){
            if(h == 1) return 'I';
            else return 'B';
        }
        else return 'F';
    }
    
    void solve(string s){ // 建树
        if(s.size() == 1){
            FBI[count++] = find(s);
            return ;
        }
        string a = s.substr(0, s.size()/2), b = s.substr(s.size()/2);
        solve(a); // 左儿子
        solve(b); // 右儿子
        FBI[count++] = find(s);
        return ;
    }
    
    int main(){
        while(cin >> N){
            cin >> s;
            count = 0;
            solve(s);
    //        printf("count:%d
    ", count);
            for(int i = 0; i < count; i++) cout << FBI[i];
            cout << endl;
        }
        return 0;
    }
    AC代码

    string的substr对于复制string屡试不爽,推荐一下。

    下一题:

    P1030 求先序排列

    前中后序排列指的是二叉树怎么查询的问题。

    推荐博客:看懂二叉树的三种遍历(比较容易理解)

    (前序排列:根左右; 中序排序:左根右;后序排序:左右根;)

    题目样例:

    手写一下,会发现:

    后序排列的末位肯定是前面所有节点的父节点;

    然后在中序排列里找到那个父节点就可以把字符串分成两部分;

    中:BADC → 中:B    DC → 中:B  D

    后:BDCA  后:B    CD → 后:B  D

    查找的同时把父节点(后序排列字符串的末尾)输出。

    (题目样例过于简单,可在上述的博客研究更复炸的树)

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 
     5 string a, b; // a是中序, b是后序
     6 
     7 void solve(string a, string b){
     8     if(b.size() > 0){
     9         cout << b[b.size()-1];
    10         int n = a.find(b[b.size()-1]);
    11         solve(a.substr(0, n), b.substr(0, n));
    12         solve(a.substr(n+1), b.substr(n, a.size()-n-1));
    13     }
    14     return ;
    15 }
    16 
    17 int main()
    18 {
    19     while(cin >> a >> b){
    20         solve(a, b);
    21         cout << endl;
    22     }
    23     return 0;
    24 }
    AC代码

    (参考了洛谷第一位题解,自己弄了一晚上把自己弄晕了@-@)

    下一题:

    P1305 新二叉树

    经过上两题的练习后,相信看到这里的你对于这题的第一感觉就可以用暴力建树解决了(没错,我就是这么解决的)

    后面n行的第一个字目表示父节点——找到父节点的序号,左右儿子就简单储存(暴力遍历)

    最后搜索一下就AC了。

    (一开始数据建少了,所以会RE与WA。要注意的是,父节点的序号是从1开始的,如果从0开始,0*2还是等于0的quq)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 int N, par;
     7 char s[5005];
     8 char t[3];
     9 
    10 void print(char s[], int i){
    11     if(s[i] == '*') return ;
    12     cout << s[i];
    13     print(s, i*2);
    14     print(s, i*2+1);
    15 
    16     return ;
    17 }
    18 int main()
    19 {
    20     cin >> N;
    21     for(int i = 0; i < 5000; i++) s[i] = '*';
    22     for(int i = 0; i < N; i++){
    23         cin >> t;
    24         if(i == 0) s[1] = t[0];
    25 
    26         for(int f = 1; f < 5000; f++){
    27             if(s[f] == t[0]) {
    28                 par = f;
    29                 break;
    30             }
    31         }
    32         s[par*2] = t[1];
    33         s[par*2+1] = t[2];
    34     }
    35 
    36     print(s, 1);
    37     cout << endl;
    38 
    39     return 0;
    40 }
    AC代码
  • 相关阅读:
    csu1217: 奇数个的那个数
    小试SAS 判别分析
    bfs poj2965
    STL set常用操作
    csu1002 A+B(III)
    HDOJ 1002 的几种方法
    SQL知识积累
    CSV文件格式介绍
    ASP.net Web Form 知识积累
    C# 位域[flags] 枚举
  • 原文地址:https://www.cnblogs.com/Ayanowww/p/10886251.html
Copyright © 2011-2022 走看看