N
(백준 c++)2250 트리의 높이와 너비 본문
문제
이진트리를 다음의 규칙에 따라 행과 열에 번호가 붙어있는 격자 모양의 틀 속에 그리려고 한다. 이때 다음의 규칙에 따라 그리려고 한다.
- 이진트리에서 같은 레벨(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이 주어진다.
출력
첫째 줄에 너비가 가장 넓은 레벨과 그 레벨의 너비를 순서대로 출력한다. 너비가 가장 넓은 레벨이 두 개 이상 있을 때에는 번호가 작은 레벨을 출력한다.
이진 트리의 높이와 너비를 구해야 한다.
dfs와 bfs를 활용하면 된다.
설명은 주석에 있으니 참고..!!
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int current_y = 1;
int max_level = 0;
bool tree[10001][10001];
struct Node{
int num;
Node * left;
Node * right;
};
//중위 탐색(left->current->right 순으로 탐색)
void dfs(Node * node, int level){
if(node->left->num != 0){
dfs(node->left, level + 1);
}
//bool형 2차원 배열을 통해 y열에 겹치지 않게 그래프를 표시
tree[level][current_y++] = true;
if(node->right->num != 0){
dfs(node->right, level + 1);
}
}
//그래프의 최대 높이(level)를 구하기 위한 bfs
void bfs(Node * root){
queue<Node*> q;
q.push(root);
while(!q.empty()){
int size = q.size();
for(int i = 0; i < size; i++){
Node * node = q.front();
q.pop();
if(node->left->num != 0){
q.push(node->left);
}
if(node->right->num != 0){
q.push(node->right);
}
}
max_level++;
}
}
int main(void){
int N;
Node * root;
int answer[2] = {1, 1};
cin >> N;
//node를 연결하기 위해 사용
vector<Node> node(N + 1);
//루트를 찾기위해 숫자를 카운트.
//num을 입력받으면서 카운팅을 시작.
//카운팅 결과 1이 나온 num이 루트 노드의 시작 숫자.
vector<int> count(N + 1, 0);
//node[0] -> 자식 노드가 없을 때 0으로 처리
node[0].num = 0;
for(int i = 1; i <= N; i++){
int num, left, right;
cin >> num >> left >> right;
node[num].num = num;
count[num]++;
//left 또는 right가 -1인 경우 node[0]으로 연결.
//그 외의 경우 node[num]을 연결시켜 준다.
if(left != -1){
node[num].left = &node[left];
count[left]++;
}
else{
node[num].left = &node[0];
}
if(right != -1){
node[num].right = &node[right];
count[right]++;
}
else{
node[num].right = &node[0];
}
}
//count 배열을 통해 루트 노드 찾기
for(int i = 1; i <= N; i++){
if(count[i] == 1){
root = &node[i];
break;
}
}
//넓이를 구하기 위해 dfs 활용
dfs(root, 1);
//높이를 구하기 위해 bfs 활용
bfs(root);
//각 레벨마다 왼쪽과 오른쪽을 탐색.
//왼쪽, 오른쪽 탐색 시 가장 처음에 만난 노드의 위치를 저장하고 답을 구한다.
for(int i = 1; i <= max_level; i++){
int tmp = 0;
int left = 0, right = N;
for(int j = 1; j <= N; j++){
if(tree[i][j]){
left = j;
break;
}
}
for(int j = N; right >= 1; j--){
if(tree[i][j]){
right = j;
break;
}
}
tmp = right - left + 1;
if(answer[1] < tmp){
answer[0] = i;
answer[1] = tmp;
}
}
cout << answer[0] << " " << answer[1];
return 0;
}