알고리즘

트리의 높이와 너비 (boj 2250)

KyooDong 2020. 6. 3. 17:52
728x90

트리의 높이와 너비 문제는 각 노드마다 자식 노드의 번호를 2개 주고, 이를 이진트리로 만든 뒤 DFS하는 문제에요 (Postorder search)

 

아래 코드를 보시면

children 배열에 자식노드를, parent 노드에 부모 노드를 저장하여 이진트리를 구성했어요.

그리고 빈 column 없이 트리를 구성해야한다는 점을 이용하면, 왼쪽 자식 서브 트리가 차지한 최대 column + 1 이 자기 자신의 노드 column index가 된다는 것을 알 수 있죠. 이후 오른쪽 자식노드의 maxIndex를 구하는 이유는 내 부모 노드의 위치를 결정해주어야 하기 때문이에요.

DFS를 통해 재귀적으로 자식의 maxIndex 부터 알아가며 자기 자신의 위치를 결정하고, 그렇게 결정된 위치를 통해 레벨 별 최소 최대 인덱스를 적절히 계산하여 너비를 구해내면 답을 쉽게 찾을 수 있습니다.

 

코드

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>

#define INF 987654321

int N;

// 자식 노드 (first = 왼쪽 노드, second = 오른쪽 자식 노드)
std::pair<int, int> children[10010];

// 부모 노드
int parent[10010];

// 최종 결과 (first = 해당 레벨에서 가장 작은 column index, second = 해당 레벨에서 가장 큰 column index)
std::pair<int, int> result[10010];

// 트리 루트
int root;

/**
 * 트리 순회 함수
 * @param curNode 현재 방문하고 있는 노드
 * @param level  현재 방문하고 있는 노드의 레벨
 * @param startColumn 현재 노드가 가질 수 있는 최소 column index - 1     즉, 현재까지 노드로 차 있는 column index 라고 생각하면 좋음
 * @return 현재 노드가 구성하는 서브트리의 max column index
 */
int DFS(int curNode, int level, int startColumn) {
    // 유효하지 않은 노드번호인 경우 startColumn 자체가 max column index
    if (curNode == 0)
        return startColumn;

    // 왼쪽 자식의 max column index 를 구함
    int left = DFS(children[curNode].first, level + 1, startColumn);

    // 나 자신은 왼쪽 자식의 max column index 바로 다음 것에 저장됨
    int position = left + 1;

    // 현재 level에서 나 자신이 가장 최소 index 이거나 최대 index 일 수 있으니 이를 업데이트
    result[level].first = std::min(result[level].first, position);
    result[level].second = std::max(result[level].second, position);

    // 오른쪽 자식의 maxIndex
    int right = DFS(children[curNode].second, level + 1, position);
    return right;
}

int main() {
    scanf("%d", &N);

    for (int n = 1; n <= N; n++) {
        int num, left, right;
        scanf("%d %d %d", &num, &left, &right);
        if (left == -1)
            left = 0;

        if (right == -1)
            right = 0;

        // 트리 구성
        // 노드 num 의 왼쪽 오른쪽 자식 노드를 세팅
        children[num].first = left;
        children[num].second = right;

        // 왼쪽 오른쪽 자식 노드 입장에서는 num이 부모 노드
        parent[left] = num;
        parent[right] = num;

        result[n].first = INF;
    }

    for (int n = 1; n <= N; n++) {
        // 부모가 없는 노드가 루트노드
        if (!parent[n]) {
            root = n;
            break;
        }
    }

    // DFS 돌리면 level 별로 최소 인덱스와 최대 인덱스가 저장되어 나옴
    DFS(root, 1, 0);

    int n1 = 0, n2 = 0;
    for (int n = 1; n <= N; n++) {
        // 최대 너비 찾기
        int width = result[n].second - result[n].first + 1;
        if (n1 < width) {
            n1 = width;
            n2 = n;
        }
    }
    printf("%d %d\n", n2, n1);
    return 0;
}