[ 백준 ] 4256 / 트리

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
189/228
post-thumbnail

# Appreciation

/*
 * Problem :: 4256 / 트리
 *
 * Kind :: Data Structure
 *
 * Insight
 * - 전위순회 결과
 *   3 6 5 4 8 7 1 2
 *   중위순회 결과
 *   5 6 8 4 3 1 2 7
 *   + 전위순회한 결과에서 가장 처음에 만나는 노드는 루트(Root)노드일 수밖에 없다
 *     따라서 루트노드는 3 이다
 *     # 중위순회한 결과에서
 *       3 왼쪽에 있는 노드들은 5 6 8 4 이며 이들은 루트노드의 왼쪽 서브트리를 이루는 노드들이다
 *       3 오른쪽에 있는 노드들은 1 2 7 이며 이들은 루트노드의 오른쪽 서브트리를 이루는 노드들이다
 *       -> 왼쪽 서브트리를 이루는 노드의 개수는 총 4개이며
 *          이에 해당하는 전위순회 결과는 3 바로 오른쪽 4개의 노드들인 6 5 4 8 에 해당한다
 *          오른쪽 서브트리를 이루는 노드의 개수는 총 3개이며
 *          이에 해당하는 전위순회 결과는 왼쪽 서브트리를 전위순회한 결과의
 *          오른쪽 3개의 노드들인 1 2 7 에 해당한다
 *          => 그럼 우리는
 *             왼쪽 서브트리에 해당하는
 *             전위순회 결과
 *             6 5 4 8
 *             중위순회 결과
 *             5 6 8 4
 *             를 통해 그 서브트리에서 루트노드를 찾을 수 있다
 *          => 마찬가지로
 *             오른족 서브트리에 해당하는
 *             전위순회 결과
 *             7 1 2
 *             후위순회 결과
 *             1 2 7
 *             를 통해 그 서브트리에서 루트노드를 찾을 수 있다
 *
 * - 추가적으로 루트노드의 왼쪽 서브트리의 경우를 살펴보자
 *   + 전위순회 결과
 *     6 5 4 8
 *     중위순회 결과
 *     5 6 8 4
 *     # 현재노드 : 6
 *       왼쪽 서브트리 중위순회 결과 : 5
 *       오른쪽 서브트리 중위순회 결과 : 8 4
 *       왼쪽 서브트리 전위순회 결과 : 5
 *       오른쪽 서브트리 중위순회 결과 : 4 8
 *       -> 현재 전위순회 결과에서 루트노드를 알아내고
 *          중위순위 결과를 통해 왼쪽 서브트리와 오른쪽 서브트리의
 *          전위순회, 중위순회 결과를 알아내서 차례로 방문하는
 *          재귀함수를 만들자!
 *
 * Point
 * - 전위순회나 중위순회나 후위순회나
 *   사실 방문하는 노트의 순서는 모두 같다
 *   + 다만, 각 재귀함수에서 출력하는 코드가
 *     방문하자마자 그 노드를 출력하는지
 *     왼쪽 서브트리를 방문하고 출력하는지
 *     왼쪽, 오른쪽 서브트리를 모두 방문하고 출력하는지
 *     차이만 있을 뿐이다
 *
 * - 전위순회 결과와 중위순회 결과만 따로 뽑아내서
 *   재귀함수의 인자로 넣어주면 좋겠지만...
 *   조금 번거롭다
 *   + 인덱스로도 충분히 다루어줄 수 있으니 그렇게 해주자
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int N;
int P[1000], I[1000], O[1000];

// Set up : Functions Declaration
void postorder(int sp, int ep, int si, int ei);


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int T; cin >> T;

    while (T--) {
        cin >> N;
        for (int i=0; i<N; i++)
            cin >> P[i]; /* 전위순회 결과 */
        for (int i=0; i<N; i++) {
            cin >> I[i]; /* 중위순회 결과 */
            O[I[i]] = i; /* O[i] = i번 노드의 중위순회 결과 인덱스 */
        }

        // Control : Output
        postorder(0, N-1, 0, N-1);
        cout << endl;
    }
}

// Helper Functions
void postorder(int sp, int ep, int si, int ei)
/* 전위순회 결과 : P[sp] ~ P[ep]
 * 중위순회 결과 : O[si] ~ O[ei]
 * 이를 통해 현재노드를 찾고
 * 루트노드의 왼쪽 서브트리와 오른쪽 서브트리를 방문 후
 * 현재 트리의 루트노드를 출력 (후위순회) */
{
    int v = P[sp]; /* node */
    int idx = O[v];
    int ln = idx - si;
    int rn = ei - idx;

    /* 왼쪽 서브트리
     * 전위순회 결과 : P[lsp] ~ P[lep]
     * 중위순회 결과 : O[lsi] ~ O[lei] */
    int lsp = sp+1, lep = sp+ln, lsi = si, lei = idx-1;
    if (lsp <= lep && lsi <= lei) /* v.left != Ø */
        postorder(lsp, lep, lsi, lei);

    /* 오른쪽 서브트리
     * 전위순회 결과 : P[rsp] ~ R[rep]
     * 중위순회 결과 : O[rsi] ~ O[rei] */
    int rsp = ep-rn+1, rep = ep, rsi = idx+1, rei = ei;
    if (rsp <= rep && rsi <= rei) /* v.right != Ø */
        postorder(rsp, rep, rsi, rei);

    cout << v << ' '; /* printf(id number of v); */
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글