문제
이진트리를 다음의 규칙에 따라 행과 열에 번호가 붙어있는 격자 모양의 틀 속에 그리려고 한다. 이때 다음의 규칙에 따라 그리려고 한다.
- 이진트리에서 같은 레벨(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이 주어진다.
출력
첫째 줄에 너비가 가장 넓은 레벨과 그 레벨의 너비를 순서대로 출력한다. 너비가 가장 넓은 레벨이 두 개 이상 있을 때에는 번호가 작은 레벨을 출력한다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
public class baekjoon2250_5 {
private static Map<String, Node2250> info;
private static Width2250[] widthInfo;
private static int order = 1;
private static int n;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
info = new HashMap<>();
widthInfo = new Width2250[n + 1];
for (int i = 1; i < n + 1; i++) {
st = new StringTokenizer(br.readLine());
String node = st.nextToken();
String leftNode = st.nextToken();
String rightNode = st.nextToken();
info.put(node, new Node2250(leftNode, rightNode));
widthInfo[i] = new Width2250();
}
String root = findRoot();
inOrder2250(root, 1);
int maxDepth = 0;
int maxWidth = 0;
for (int i = 1; i < n + 1; i++) {
if (widthInfo[i].getWidth() > maxWidth) {
maxWidth = widthInfo[i].getWidth();
maxDepth = i;
}
}
System.out.printf("%s %s", maxDepth, maxWidth);
}
private static void inOrder2250(String currentNode, Integer depth) {
if (currentNode.equals("-1")) {
return;
}
// System.out.println(info.get(currentNode).left);
inOrder2250(info.get(currentNode).left, depth + 1);
Width2250 currentWidth = widthInfo[depth];
currentWidth.setLeft(order);
currentWidth.setRight(order);
order++;
inOrder2250(info.get(currentNode).right, depth + 1);
}
private static String findRoot() {
ArrayList<String> rootInfo = new ArrayList<>();
for (String parent : info.keySet()) {
String leftChild = info.get(parent).left;
String rightChild = info.get(parent).right;
rootInfo.add(leftChild);
rootInfo.add(rightChild);
}
for (String parent : info.keySet()) {
if (!rootInfo.contains(parent)) {
return parent;
}
}
throw new IllegalArgumentException("root find error");
}
}
class Node2250 {
String left;
String right;
public Node2250(String left, String right) {
this.left = left;
this.right = right;
}
}
class Width2250 {
int left;
int right;
public Width2250() {
this.left = 0;
this.right = 0;
}
public void setLeft(int left) {
if (this.left == 0) {
this.left = left;
return;
}
if (this.left >= left) {
this.left = left;
}
}
public void setRight(int right) {
if (this.right == 0) {
this.right = right;
return;
}
if (this.right <= right) {
this.right = right;
}
}
public int getWidth() {
return right - left + 1;
}
}
'알고리즘 > 초급1' 카테고리의 다른 글
[JAVA] 1167번: 트림의 지름 ( 초급 2-57 ) - fail (0) | 2021.11.02 |
---|---|
[JAVA] 백준 11725번: 트리의 부모 찾기 ( 초급 2-56 ) (0) | 2021.10.29 |
백준: 1991번: 트리 순회 ( 초급 2-54 ) (0) | 2021.10.27 |
[JAVA] 백준 1261번: 알고스팟 ( 초급 2-53 ) - hard (0) | 2021.10.25 |
[JAVA] 백준 13549번: 숨바꼭질 3 ( 초급 2-52 ) - hard (0) | 2021.10.25 |