공부혜옹

백준 2250번 트리의 높이와 너비 본문

공부합시다/Algorithm

백준 2250번 트리의 높이와 너비

Blair06 2021. 4. 20. 22:09

트리의 높이와 너비 

시간 제한메모리 제한제출정답맞은 사람정답 비율

2 초 128 MB 11659 3219 2199 27.148%

문제

이진트리를 다음의 규칙에 따라 행과 열에 번호가 붙어있는 격자 모양의 틀 속에 그리려고 한다. 이때 다음의 규칙에 따라 그리려고 한다.

  1. 이진트리에서 같은 레벨(level)에 있는 노드는 같은 행에 위치한다.
  2. 한 열에는 한 노드만 존재한다.
  3. 임의의 노드의 왼쪽 부트리(left subtree)에 있는 노드들은 해당 노드보다 왼쪽의 열에 위치하고, 오른쪽 부트리(right subtree)에 있는 노드들은 해당 노드보다 오른쪽의 열에 위치한다.
  4. 노드가 배치된 가장 왼쪽 열과 오른쪽 열 사이엔 아무 노드도 없이 비어있는 열은 없다.

이와 같은 규칙에 따라 이진트리를 그릴 때 각 레벨의 너비는 그 레벨에 할당된 노드 중 가장 오른쪽에 위치한 노드의 열 번호에서 가장 왼쪽에 위치한 노드의 열 번호를 뺀 값 더하기 1로 정의한다. 트리의 레벨은 가장 위쪽에 있는 루트 노드가 1이고 아래로 1씩 증가한다.

아래 그림은 어떤 이진트리를 위의 규칙에 따라 그려 본 것이다. 첫 번째 레벨의 너비는 1, 두 번째 레벨의 너비는 13, 3번째, 4번째 레벨의 너비는 각각 18이고, 5번째 레벨의 너비는 13이며, 그리고 6번째 레벨의 너비는 12이다.

우리는 주어진 이진트리를 위의 규칙에 따라 그릴 때에 너비가 가장 넓은 레벨과 그 레벨의 너비를 계산하려고 한다. 위의 그림의 예에서 너비가 가장 넓은 레벨은 3번째와 4번째로 그 너비는 18이다. 너비가 가장 넓은 레벨이 두 개 이상 있을 때는 번호가 작은 레벨을 답으로 한다. 그러므로 이 예에 대한 답은 레벨은 3이고, 너비는 18이다.

임의의 이진트리가 입력으로 주어질 때 너비가 가장 넓은 레벨과 그 레벨의 너비를 출력하는 프로그램을 작성하시오

입력

첫째 줄에 노드의 개수를 나타내는 정수 N(1 ≤ N ≤ 10,000)이 주어진다. 다음 N개의 줄에는 각 줄마다 노드 번호와 해당 노드의 왼쪽 자식 노드와 오른쪽 자식 노드의 번호가 순서대로 주어진다. 노드들의 번호는 1부터 N까지이며, 자식이 없는 경우에는 자식 노드의 번호에 -1이 주어진다.

출력

첫째 줄에 너비가 가장 넓은 레벨과 그 레벨의 너비를 순서대로 출력한다. 너비가 가장 넓은 레벨이 두 개 이상 있을 때에는 번호가 작은 레벨을 출력한다.


각 레벨의 너비를 구하고 그 너비가 가장 큰 레벨과 너비를 출력해주면 되는 문제였다.
처음에는 각 레벨에서 가장 왼쪽노드와 가장 오른쪽 노드를 구할때 (구하는 이유: 가장 외곽에 있는 노드들의 너비를 더한후 -1한것이 최대 너비이기때문) LCA문제처럼 부모배열과 깊이배열을 사용해 구하려고 하다가 이진트리이기 때문에 굳이 그런 방식으로 풀진 않았다.

 

트리를 만든 후 루트를 찾고,  dfs를 이용해 더 깊은 곳에 있는 자식노드들 까지 확인해주면서 각 레벨의 가장 외곽의 노드 두개를 찾아 Min, Max 배열에 넣어주었다.
이후, for문을 이용해 각 레벨별로 최대 너비를 구한 후 비교해 출력해주었다.

#include <iostream>
#include <queue>
#include<algorithm>
#include <limits.h>
using namespace std;
 

int Min[10002];
int Max[10002];

pair<int, int> tree[10001];
pair<int, int> lev[10001];
int n,m;
int sum, maxval, depth;
int isroot[10001];
int pos = 1; // 노드의 위치

void func(int cur, int level){
    //자식이 있으면 깊이를 증가해 dfs
    if (tree[cur].first > 0){
        func(tree[cur].first, level + 1);
    }
    lev[cur].first = level;
    lev[cur].second = pos;
           
    // 현재 레벨에서 가장 왼쪽 노드 위치를 갱신
    if (Min[lev[cur].first] > lev[cur].second){
        Min[lev[cur].first] = lev[cur].second;

    }
    
   // 현재 레벨에서 가장 오른쪽 노드 위치를 갱신
   if (Max[lev[cur].first] < lev[cur].second)
       Max[lev[cur].first] = lev[cur].second;

   pos++;
    
    // 오른쪽 자식이 있다면
    if (tree[cur].second > 0){
        func(tree[cur].second, level + 1);
    }
           

}
int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n;
    fill(Min, Min + 10002, INT_MAX);

    for(int i=1; i<=n; i++){
        int a,b,c;
        cin >> a >> b >> c;
        tree[a].first=b;
        tree[a].second=c;
        isroot[a]++;
        if (b != -1){
            isroot[b]++;
        }
        if (c != -1){
            isroot[c]++;
        }
    }
    //루트노드는 증가를 한번만 했기 때문에 1인 상태
    int root=0;
    for(int i=1; i<= n; i++){
        if(isroot[i] == 1){
            root = i;
        }
    }
    func(root,1);
    for (int i = 1; i <= n; i++)
        {
            sum = Max[i] - Min[i] + 1;
            if (sum > maxval)
            {
                maxval = sum;
                depth = i;
            }
        }

    cout << depth << ' ' << maxval ;
    
    return 0;
}
반응형

'공부합시다 > Algorithm' 카테고리의 다른 글

백준 1062번 가르침  (0) 2021.04.27
백준 15787번 기차가 어둠을 헤치고 은하수를  (0) 2021.04.24
백준 11437번 LCA  (0) 2021.04.20
백준 1068번 트리  (0) 2021.04.20
백준 1981번 배열에서 이동  (0) 2021.04.13
Comments