알고리즘/문제 풀이

5639번: 이진 검색 트리

Themion 2021. 12. 23. 17:14

https://www.acmicpc.net/problem/5639

 

5639번: 이진 검색 트리

트리를 전위 순회한 결과가 주어진다. 노드에 들어있는 키의 값은 106보다 작은 양의 정수이다. 모든 값은 한 줄에 하나씩 주어지며, 노드의 수는 10,000개 이하이다. 같은 키를 가지는 노드는 없다

www.acmicpc.net

트리를 배열로 저장했을 때, 트리의 인덱스 범위 [s, e)에 대해 루트 노드는 항상 s에 있고, 왼쪽 서브 트리와 오른쪽 서브 트리는 어느 경계를 기점으로 나뉘어 있다.

범위 (s, e)에 대해 lower_bound를 실행할 경우 왼쪽 서브 트리와 오른쪽 서브 트리, 즉 값이 루트 노드보다 작은 부분과, 값이 루트 노드보다 크거나 같은 부분을 나누는 지점을 찾을 수 있다. 이 때 오른쪽 서브 트리에는 루트 노드와 같은 값을 갖는 노드가 존재하지 않으므로, lower_bound를 실행해 얻은 인덱스 m에 대해 범위 [s + 1, m)은 왼쪽 서브 트리, 범위 [m, e)는 오른쪽 서브 트리라고 볼 수 있다.

이 과정을 재귀를 통해 반복하면 트리를 복원할 수 있고, 이 복원된 트리를 후위 순회한 결과를 출력하면 정답을 얻을 수 있다.

#include <algorithm>
#include <cstdio>

// 트리를 전위 순회한 결과를 저장한 배열
int tree[10000];

using namespace std;

// 트리의 인덱스 범위 [s, e)에서 전위 순회를 후위 순회로 전환
void f2b(int s, int e) {
    // 트리가 존재하지 않아 범위에 오류가 발생할 경우 return
    if (s >= e) return;
    // 범위가 1인 경우 루트 노드만 존재하므로 루트 노드를 출력한 뒤 종료
    if (e - s == 1) {
        printf("%d\n", tree[s]);
        return;
    }

    // 현재 노드의 왼쪽 서브트리가 끝나는 인덱스
    // 범위 (s, e)에서 lower_bound를 실행할 경우
    // 두 서브 트리를 나누는 지점을 정확히 찾을 수 있다
    int m = lower_bound(tree + s + 1, tree + e, tree[s]) - tree;

    // 후위 순회 실행
    f2b(s + 1, m);
    f2b(m, e);
    printf("%d\n", tree[s]);
}

int main() {
    // 전체 트리의 길이
    int len = 0;
    // 트리를 입력받는다
    for (; scanf("%d", tree + len) != EOF && tree[len]; len++);
    // 전위 순회의 결과를 후위 순회로 전환
    f2b(0, len);

    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

6064번: 카잉 달력  (0) 2021.12.24
5696번: 숫자 세기  (0) 2021.12.23
5622번: 다이얼  (0) 2021.12.23
5597번: 과제 안 내신 분..?  (0) 2021.12.23
5582번: 공통 부분 문자열  (0) 2021.12.23