https://www.acmicpc.net/problem/2250
2250번: 트리의 높이와 너비
첫째 줄에 노드의 개수를 나타내는 정수 N(1 ≤ N ≤ 10,000)이 주어진다. 다음 N개의 줄에는 각 줄마다 노드 번호와 해당 노드의 왼쪽 자식 노드와 오른쪽 자식 노드의 번호가 순서대로 주어진다.
www.acmicpc.net
문제
이진트리를 다음의 규칙에 따라 행과 열에 번호가 붙어있는 격자 모양의 틀 속에 그리려고 한다. 이때 다음의 규칙에 따라 그리려고 한다.
- 이진트리에서 같은 레벨(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이 주어진다.
출력
첫째 줄에 너비가 가장 넓은 레벨과 그 레벨의 너비를 순서대로 출력한다. 너비가 가장 넓은 레벨이 두 개 이상 있을 때에는 번호가 작은 레벨을 출력한다.

#include <iostream>
#include <deque>
using namespace std;
int N;
int tree[10001][2];
int findRoot[10001];
int root;
deque<int> col[10001];
int index = 1;
void inorder(int a, int count)
{
if (tree[a][0] > 0)
{
inorder(tree[a][0], count+1);
}
col[count].push_back(index);
index++;
if (tree[a][1] > 0)
{
inorder(tree[a][1], count+1);
}
return;
}
int main()
{
//입력
cin >> N;
for (int i = 1; i <= N; i++)
{
int x, y, z;
cin >> x >> y >> z;
tree[x][0] = y;
tree[x][1] = z;
}
//루트찾기
for (int i = 1; i <= N; i++)
{
if (tree[i][0] > 0)
{
findRoot[tree[i][0]]++;
}
if (tree[i][1] > 0)
{
findRoot[tree[i][1]]++;
}
}
for (int i = 1; i <= N; i++)
{
if (findRoot[i] == 0)
root = i;
}
//중위 순회
inorder(root, 1);
//결과
int rowAns=1;
int high=0;
for (int i = N; i>=1; i--)
{
if (col[i].empty())
continue;
int tmp = col[i].back() - col[i].front()+1;
if (tmp >= high)
{
high = tmp;
rowAns = i;
}
}
cout << rowAns << ' ' << high;
}
위 그림에서 열의 순서 번호는 중위순회를 따라간다는 것을 알 수 있다.
중위순회를 돌기위해 먼저 루트를 찾아주고, 중위순회를 돌며 해당 레벨의 deque에 현재 순회 순서를 넣어준다.
마지막으로 판별 할 때 덱의 front와 back을 빼주면 그 값이 너비가 된다.
'백준 c++ > (1-2)백준 c++ 알고리즘 기초' 카테고리의 다른 글
백준 11725 c++ 트리의 부모 찾기 (0) | 2023.01.23 |
---|---|
백준 1991 c++ 트리 순회 (0) | 2023.01.17 |
백준 2146 다리 만들기 c++ (0) | 2023.01.16 |
백준 16964 DFS 스페셜 저지 c++ (0) | 2023.01.15 |
백준 16940 BFS 스페셜 저지 c++ (0) | 2023.01.13 |