상근이는 슬로베니아의 도시 Donji Andrijevci를 여행하고 있다. 이 도시의 도로는 깊이가 K인 완전 이진 트리를 이루고 있다. 깊이가 K인 완전 이진 트리는 총 2K-1개의 노드로 이루어져 있다. (아래 그림) 각 노드에는 그 곳에 위치한 빌딩의 번호가 붙여져 있다. 또, 가장 마지막 레벨을 제외한 모든 집은 왼쪽 자식과 오른쪽 자식을 갖는다.
깊이가 2와 3인 완전 이진 트리
상근이는 도시에 있는 모든 빌딩에 들어갔고, 들어간 순서대로 번호를 종이에 적어 놓았다. 한국으로 돌아온 상근이는 도시가 어떻게 생겼는지 그림을 그려보려고 하였으나, 정확하게 기억이 나지 않아 실패했다. 하지만, 어떤 순서로 도시를 방문했는지 기억해냈다.
왼쪽 그림에 나와있는 마을이라면, 상근이는 2-1-3 순서대로 빌딩을 들어갔을 것이고, 오른쪽 그림의 경우에는 1-6-4-3-5-2-7 순서로 들어갔을 것이다. 상근이가 종이에 적은 순서가 모두 주어졌을 때, 각 레벨에 있는 빌딩의 번호를 구하는 프로그램을 작성하시오.
첫째 줄에 K (1 ≤ K ≤ 10)가 주어진다.
둘째 줄에는 상근이가 방문한 빌딩의 번호가 들어간 순서대로 주어진다. 모든 빌딩의 번호는 중복되지 않으며, 구간 [1,2K)에 포함된다.
총 K개의 줄에 걸쳐서 정답을 출력한다. i번째 줄에는 레벨이 i인 빌딩의 번호를 출력한다. 출력은 왼쪽에서부터 오른쪽 순서대로 출력한다.
2
2 1 3
1
2 3
3
1 6 4 3 5 2 7
3
6 2
1 4 5 7
상근이가 빌딩🏢을 방문하는 순서를 살펴보면, 중위 순회(inorder traversal)로 방문하고 있는 것을 알 수 있습니다.
- 중위 순회 순서
왼쪽 자식 노드 ➡ 현재 노드 ➡ 오른쪽 자식 노드
따라서, 완전 이진 트리를 중위 순회하는 순서에 맞게 빌딩의 번호를 맞추어 넣으면 됩니다.
이 때, 완전 이진 트리는 다음과 같은 특징을 가집니다.
노드를 리스트에 저장하는 경우,
번째 인덱스에 있는 노드의 왼쪽 자식은 ,
오른쪽 자식은 입니다.
import sys
input = sys.stdin.readline
K = int(input())
nums = list(map(int, input().split())) # 방문한 순서를 담은 리스트
nums.reverse()
tree = [0 for _ in range(2 ** K)] # 빌딩 번호 완전이진트리 리스트
def make_tree(tree, nums, root): # 중위 순회 순서대로 빌딩 번호 세팅
if root < 1 or 2 ** K <= root or tree[root] != 0: return
make_tree(tree, nums, 2 * root) # 왼쪽 자식 노드 탐색
tree[root] = nums.pop() # 빌딩 번호 할당
make_tree(tree, nums, 2 * root + 1) # 오른쪽 자식 노드 탐색
make_tree(tree, nums, 1)
i = 1
while i < 2 ** K: # 출력 반복문
for j in range(i, i * 2):
print(tree[j], end=' ')
print()
i *= 2