공부혜옹
백준 2250번 트리의 높이와 너비 본문
트리의 높이와 너비
시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초 | 128 MB | 11659 | 3219 | 2199 | 27.148% |
문제
이진트리를 다음의 규칙에 따라 행과 열에 번호가 붙어있는 격자 모양의 틀 속에 그리려고 한다. 이때 다음의 규칙에 따라 그리려고 한다.
- 이진트리에서 같은 레벨(level)에 있는 노드는 같은 행에 위치한다.
- 한 열에는 한 노드만 존재한다.
- 임의의 노드의 왼쪽 부트리(left subtree)에 있는 노드들은 해당 노드보다 왼쪽의 열에 위치하고, 오른쪽 부트리(right subtree)에 있는 노드들은 해당 노드보다 오른쪽의 열에 위치한다.
- 노드가 배치된 가장 왼쪽 열과 오른쪽 열 사이엔 아무 노드도 없이 비어있는 열은 없다.
이와 같은 규칙에 따라 이진트리를 그릴 때 각 레벨의 너비는 그 레벨에 할당된 노드 중 가장 오른쪽에 위치한 노드의 열 번호에서 가장 왼쪽에 위치한 노드의 열 번호를 뺀 값 더하기 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 |