[NOIP2004 Popularization Group] FBI tree queue solution

[NOIP2004 Popularization Group] FBI Tree

Title description:

We can divide the strings composed of 0 and 1 into three categories: all 0 strings are called B strings, all 1 strings are called I strings, and strings containing both 0 and 1 are called F strings.

The FBI tree is a binary tree, and its node types also include three types: F node, B node and I node. An FBI tree T can be constructed from a 01 string S with a length of $2^N$, and the recursive construction method is as follows:

1. The root node of T is R, whose type is the same as that of string S;
2. If the length of string S is greater than 1, split string S from the middle, and divide it into left and right substrings S1 and S2 of equal length; The substring S1 constructs the left subtree T1 of R, and the right subtree T2 of R is constructed from the right substring S2.

Now given a 01 string with a length of 2^N, please use the above construction method to construct an FBI tree, and output its postorder traversal sequence.

input format

The first line is an integer N(0≤N≤10),

The second line is a 01 string of length 2^N.

output format

A string, the post-order traversal sequence of the FBI tree.

Input and output samples

Input #1:

3
10001011

Output #1:

IBFBBBFIBFIIIFF

Instructions/Tips

For %40% of the data, N≤2;

N≤10 for all data.

Question 3 of noip2004 popularization group.

The main idea of ​​the topic:

   The general idea of ​​the topic is that given a sequence, such as 10001011 , we have separated the sequence from the middle, the left subtree is the left subtree, and the right subtree is the right subtree. According to whether each segment is all 0 and all 1 or all 10, there are values ​​F, B, I, build a binary tree and output it in reverse order .

Recursive solution:

  This solution is much simpler than the queue solution.

[NOIP2004 Popularization Group] FBI tree recursive solution icon-default.png?t=N4P3http://t.csdn.cn/YK8MW

Queue solution:

How to get the postorder output of a binary tree?

We only need to get the hierarchical traversal of this binary tree and put it in an array. The post-order traversal code is as follows
(the general idea is to first determine whether the left subtree exists, if it exists, traverse it, then traverse the right subtree, and finally output the root node )

void print(ll h) {
    ll l=h*2,r=h*2+1;
    if(l<=size) 
	  print(l);
    if(r<=size) 
	  print(r);
    cout<<S[h];
}

Now we just need to get the level traversal array of this binary tree

For the sequence at the beginning, we split it from the middle, that is, into two parts 1000 and 1011. At the beginning, this sequence has both 0 and 1, so the root node is F, and the left subtree of F is 1000, which is F, and the right subtree 1011 is also F, and we store these three values ​​in the hierarchical traversal array in turn.

Next, we need to traverse the value of the left subtree in two parts. Note that if it is a hierarchical traversal, we cannot simply use recursion to solve it. If we use recursion, we will recurse until the deepest leaf node and then start to the right. .

As shown in the figure below, we need to sequentially put the values ​​of 10 00 10 11 into the hierarchical traversal array, but if we use recursion to solve the two ranges, similar to the code in the figure below, we will first solve the left part and then the right part. Divide into 10 and 00 for the first time, then enter 10 and divide into 1 and 0 into the array, then come out and enter 00 on the right, and then enter to store two 0s.

However, our requirement is to divide 1000 into two values ​​and store them in the array, and then directly traverse 1011 instead of continuing to traverse the subtree of 1000. We should put the subtree part in the next range to solve

So how to solve this problem?
After we divide it into 1000 and 1011, shouldn't these two ranges be further divided into smaller ones, and then stored in the hierarchical traversal array? Then we can store the unprocessed ones in a data structure. After 1000 is divided into 10 and 00, we will not process these two ranges temporarily, and store them in the data structure for later processing.
So which data structure is suitable for storing data? Let’s think about the characteristics of storage. The ones stored first are processed first, and the ones stored later are processed later. This just fits a data structure—queue. For 1000 and 1011, we First process 1000, divide it into two parts 10 and 00, we will not process these two ranges temporarily, store them in the queue, and then process 1011, after dividing into 10 and 11, it is also stored in the queue, and the structure of the queue at this time is Such

After storing these four corresponding letters 10(F) 00(B) 10(F) 11(I) into the hierarchical traversal array, we get 10 from the head of the team, and then do further processing, and continue the value after processing Putting into the queue indicates the range to be processed by the next layer.

In this way, until there is no element in the queue indicating that the FBI tree has been completely constructed, then the corresponding hierarchical traversal array is also obtained , and we can use the above code to output the postorder of the tree

Analysis code

For the queue, you can use the queue in the stl library. Here I simulate a queue with an array. Of course, you can also write a queue by hand.
We store the initial range from 1 to 2^N into the queue, which is also The first element we want to process

head points to the head of our current queue, and tail is the tail of our queue, which is the last piece of data to be processed at present. The queue starts counting from 0, and the position of tail has no data . For each range, there is a left boundary and a boundary. So we define a structure and store this structure in the queue every time

struct Node{
    ll l,r;
}Q[10020];

    ll h=-1,d=1,p,q;
    Q[++h].l=l;
    Q[h].r=r;

As long as there are elements in the current queue, we need to process them, so the exit condition of the loop is head==tail (indicating that the head of the queue has reached the empty end of the queue)

Every time head is used to fetch the head of the current queue, zero and one are used to judge whether the range is all 1 or all 0 (if there is a 1 in the middle, then all 0 zero is false, if there is a 0 in the middle, then all 1 One is false, and finally if both are false, it means that both are F, I and B, and so on)

After processing this range, we will queue this data, and then insert the hierarchical traversal array (cnt represents the number of current traversal arrays, initially 0), which is head++, if there is a sub-range under this range, then we will sub-range Divide into two parts and continue to insert at the end of the queue

    bool f1,f2;
    while(h<d){
        p=Q[h].l;
        q=Q[h].r;
        f1=f2=true;
        for(ll i=p;i<=q;i++){
            if(T[i]=='1') 
			  f1=false;
            else if(T[i]=='0') 
			  f2=false;
        }
        if(!f1&&!f2)
          S[++size]='F';
        else if(f2&&!f1)
          S[++size]='I';
        else if(f1&&!f2)
          S[++size]='B';
        h++;
        if(p<q){
            Q[d].l=p;
            Q[d++].r=(p+q)/2;
            Q[d].l=(p+q)/2+1;
            Q[d++].r=q;
        }
    }

After obtaining the hierarchical traversal array, we can directly traverse the sequence

The complete code is as follows:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,size;
char S[10020];
char T[1050];
struct Node{
    ll l,r;
}Q[10020];
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
void print(ll h) {
    ll l=h*2,r=h*2+1;
    if(l<=size) 
	  print(l);
    if(r<=size) 
	  print(r);
    cout<<S[h];
}
void FBI(ll l,ll r){
    ll h=-1,d=1,p,q;
    Q[++h].l=l;
    Q[h].r=r;
    bool f1,f2;
    while(h<d){
        p=Q[h].l;
        q=Q[h].r;
        f1=f2=true;
        for(ll i=p;i<=q;i++){
            if(T[i]=='1') 
			  f1=false;
            else if(T[i]=='0') 
			  f2=false;
        }
        if(!f1&&!f2)
          S[++size]='F';
        else if(f2&&!f1)
          S[++size]='I';
        else if(f1&&!f2)
          S[++size]='B';
        h++;
        if(p<q){
            Q[d].l=p;
            Q[d++].r=(p+q)/2;
            Q[d].l=(p+q)/2+1;
            Q[d++].r=q;
        }
    }
}
int main(){
    n=read();
    for(ll i=1;i<=pow(2,n);i++)
      cin>>T[i];
    FBI(1,pow(2,n));
    print(1);
    return 0;
}

 Summarize:

  This problem is relatively simple, and there is also a direct recursive way to achieve it.

Topic Link:
[NOIP2004 Popularization Group] FBI Tree - Luogu https://www.luogu.com.cn/problem/P1087

Guess you like

Origin blog.csdn.net/wo_ai_luo_/article/details/130933874
Recommended