Search

PGS 길 찾기 게임

태그
그래프 이론
그래프 탐색
트리
깊이 우선 탐색
생성일
2025/03/05 02:30

문제 설명

주어진 좌표 정보로 이진 트리를 구성한 후, 전위 순회와 후회 순회 결과를 반환하는 문제

예제 입력/출력

nodeinfo
result
[[5,3],[11,5],[13,3],[3,5],[6,1],[1,3],[8,6],[7,2],[2,2]]
[[7,4,6,9,1,8,5,2,3],[9,6,5,8,1,4,3,2,7]]

제약 조건

1nodeinfo10,0001 ≤ |nodeinfo| ≤ 10,000
00 ≤ 모든 노드의 좌표 값 100,000≤ 100,000

문제 풀이

문제 의도
1.
이진 탐색 트리(BST)를 만들 수 있는지?
2.
전위 순회(preorder)의 개념을 알고 있는지?
3.
후위 순회(postorder)의 개념을 알고 있는지?
접근1 이진 탐색 트리 초기화
이진 탐색 트리를 구현하기 위해 준비되어야 하는 것은 트리의 노드이다.
노드는 아래의 3개 필드를 가진다.
1.
Data: 노드의 실질적 데이터가 들어가는 필드
2.
Left: 노드의 왼쪽 자식 노드
3.
Right: 노드의 오른쪽 자식 노드
data 필드에는 각 노드의 x좌표, y좌표, 그리고 해당 노드의 고유 인덱스를 저장한다.
이진 탐색 트리를 구성하기 위한 노드를 정의하기 위해 다음과 같이 Node 클래스를 정의했다.
class Node: def __init__(self, id, x, y): self.id = id self.x = x self.y = y self.left = None self.right = None N = len(nodeinfo) # 1. 트리 생성 node_list = [] for i in range(N): node_list.append(Node(i + 1, nodeinfo[i][0], nodeinfo[i][1]))
Python
복사
접근2 이진 탐색 트리 삽입
이제 이진 탐색 트리의 삽입 연산 메소드를 통해 트리를 생성할텐데 그 전에 정렬을 한번 해주어야 한다.
문제에서 주어진 조건에 따라, y값이 클수록 상위 레벨에 위치한다.
따라서 y값이 큰 노드부터 차례대로 트리에 삽입해야한다.
정렬을 하는 여러 가지 방법이 있겠지만, __it__ 메서드를 활용하면 객체 간의 비교 연산을 수행할 수 있어 정렬이 더욱 직관적으로 가능하다.
정렬 기준은 먼저 y값을 내림차순하고 y값이 같다면 x값을 오름차순 하도록 해주었다.
class Node: def __lt__(self, other): if (self.y == other.y): return self.x < other.x return self.y > other.y node_list.sort()
Python
복사
정렬이 완료되면 삽입 연산 메소드(addNone)를 구현한다.
매개변수로 parent(부모 노드)와 child(삽입할 자식 노드)를 받는다.
현재 노드보다 자식 노드가 x 좌표가 작고, 현재 노드의 왼쪽 자식이 비어있다면 왼쪽으로 삽입한다.
이때, 왼쪽 자식이 이미 존재한다면 삽입이 불가능하므로 재귀 호출을 한다.
그 반대라면 오른쪽에 삽입한다.
이때, 오른쪽 자식이 이미 존재한다면 삽입이 불가능하므로 재귀 호출을 한다.
def addNode(parent, child): if child.x < parent.x: if parent.left is None: parent.left = child else: addNode(parent.left, child) else: if parent.right is None: parent.right = child else: addNode(parent.right, child)
Python
복사
node_list는 y값을 내림차순으로 정렬한 노드 리스트이므로 첫 번째 노트가 루트(root)가 된다. 이후 모든 노드를 addNone를 사용해 삽입한다.
root = node_list[0] for i in range(1, N): addNode(root, node_list[i])
Python
복사
접근3 전위 순회, 후위 순회
전위 순회루트 → 왼쪽 서브트리 → 오른쪽 서브트리 순으로 노드의 방문 순서를 리스트에 저장하여 반환한다.
def preorder(ans, node): # Base Case if node is None: return # Recursive Case ans.append(node.id) preorder(ans, node.left) preorder(ans, node.right) return ans answer = [[], []] preorder(answer[0], root)
Python
복사
후위 순회는 왼쪽 서브트리 → 오른쪽 서브트리 → 루트 순으로 노드의 방문 순서를 리스트에 저장하여 반환한다.
def postorder(ans, node): # Base Case if node is None: return # Recursive Case postorder(ans, node.left) postorder(ans, node.right) ans.append(node.id) return ans answer = [[], []] postorder(answer[1], root)
Python
복사

풀이 코드

import sys sys.setrecursionlimit(10**6) class Node: def __init__(self, id, x, y): self.id = id self.x = x self.y = y self.left = None self.right = None def __lt__(self, other): if (self.y == other.y): return self.x < other.x return self.y > other.y def addNode(parent, child): if child.x < parent.x: if parent.left is None: parent.left = child else: addNode(parent.left, child) else: if parent.right is None: parent.right = child else: addNode(parent.right, child) def preorder(ans, node): # Base Case if node is None: return # Recursive Case ans.append(node.id) preorder(ans, node.left) preorder(ans, node.right) return ans def postorder(ans, node): # Base Case if node is None: return # Recursive Case postorder(ans, node.left) postorder(ans, node.right) ans.append(node.id) return ans def solution(nodeinfo): N = len(nodeinfo) # 1. 트리 생성 node_list = [] for i in range(N): node_list.append(Node(i + 1, nodeinfo[i][0], nodeinfo[i][1])) node_list.sort() root = node_list[0] for i in range(1, N): addNode(root, node_list[i]) # 2. 순회 answer = [[], []] preorder(answer[0], root) postorder(answer[1], root) return answer
Python
복사

참고 자료