알고리즘 풀이/백준

[백준 1068] 트리

mhko411 2021. 4. 4. 21:40
728x90

문제

트리에서 리프 노드란, 자식의 개수가 0인 노드를 말한다.

트리가 주어졌을 때, 노드 하나를 지울 것이다. 그 때, 남은 트리에서 리프 노드의 개수를 구하는 프로그램을 작성하시오. 노드를 지우면 그 노드와 노드의 모든 자손이 트리에서 제거된다.

예를 들어, 다음과 같은 트리가 있다고 하자.

현재 리프 노드의 개수는 3개이다. (초록색 색칠된 노드) 이때, 1번을 지우면, 다음과 같이 변한다. 검정색으로 색칠된 노드가 트리에서 제거된 노드이다.

이제 리프 노드의 개수는 1개이다.

 

입력

첫째 줄에 트리의 노드의 개수 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에는 0번 노드부터 N-1번 노드까지, 각 노드의 부모가 주어진다. 만약 부모가 없다면 (루트) -1이 주어진다. 셋째 줄에는 지울 노드의 번호가 주어진다.

 

출력

첫째 줄에 입력으로 주어진 트리에서 입력으로 주어진 노드를 지웠을 때, 리프 노드의 개수를 출력한다.


접근

트리의 구조를 설계하는 것과 특징을 이해할 수 있었다.

특히 이 문제에서 알게된 것은 루트노드가 리프노드가 될 수 있다는 것이다.

 

그리고 1967문제의 트리의 지름에서 트리를 구현할 때 무방향 그래프처럼 구조를 잡았고 이 문제에서는 방향 그래프로 구조를 잡았다. 왜냐하면 이 문제의 경우 루트 노드가 주어지고 구조가 일정하다. 하지만 트리의 지름을 구할 때는 루트 노드가 주어지지않고 임의의 노드를 루트로 잡아서 탐색을 해야하기 때문이다.

 

구현

먼저 문제에서 입력받아야하는 것을 모두 입력받는다.

삭제할 노드는 del_node에 저장한다.

N = int(input())
tree_info = list(map(int, input().split()))
del_node = int(input())
tree = [[] for _ in range(N)]

 

이제 N개의 트리 정보를 입력받는다.

idx의 부모 노드는 tree_info[idx]이다. 따라서 tree라는 2차원 배열에 해당 인덱스의 자식들을 추가한다.

그리고 -1일 때는 루트 노드이고 start_node에 넣는다. 또한 삭제할 노드는 처음부터 tree에 추가하지 않는다.

for idx in range(N):
    if tree_info[idx] == -1 or tree_info[idx] == del_node:
        if tree_info[idx] == -1:
            start_node = idx
        continue
    if idx == del_node:
        continue
    tree[tree_info[idx]].append(idx)

 

만약 루트 노드와 삭제할 노드가 같다면 0을 출력하고 그렇지 않다면 리프 노드의 개수를 찾기위한 탐색을 진행한다.

if start_node == del_node:
    answer = 0
else:
    answer = bfs(start_node)

 

트리의 노드는 한 번만 방문하도록 하고 입력받은 루트 노드를 시작으로 BFS를 한다.

현재 큐의 FRONT에 있는 값의 노드에 자식 노드가 없다면 최종해를 증가시킨다.

만약 자식 노드가 존재한다면 방문 표시를 하고 큐에 넣는다.

def bfs(start):
    visited = [False] * N
    q = deque()
    visited[start] = True
    q.append(start)
    result = 0
    while q:
        parent = q.popleft()

        if len(tree[parent]) == 0:
            result += 1
            continue

        for child in tree[parent]:
            if not visited[child]:
                q.append(child)
                visited[child] = True
    return result

전체 코드

import sys
from _collections import deque

input = sys.stdin.readline

def bfs(start):
    visited = [False] * N
    q = deque()
    visited[start] = True
    q.append(start)
    result = 0
    while q:
        parent = q.popleft()

        if len(tree[parent]) == 0:
            result += 1
            continue

        for child in tree[parent]:
            if not visited[child]:
                q.append(child)
                visited[child] = True
    return result

N = int(input())
tree_info = list(map(int, input().split()))
del_node = int(input())
tree = [[] for _ in range(N)]

for idx in range(N):
    if tree_info[idx] == -1 or tree_info[idx] == del_node:
        if tree_info[idx] == -1:
            start_node = idx
        continue
    if idx == del_node:
        continue
    tree[tree_info[idx]].append(idx)


if start_node == del_node:
    answer = 0
else:
    answer = bfs(start_node)
print(answer)

'알고리즘 풀이 > 백준' 카테고리의 다른 글

[백준 9372] 상근이의 여행  (0) 2021.04.05
[백준 1991] 트리 순회  (0) 2021.04.05
[백준 1967] 트리의 지름  (0) 2021.04.04
[백준 1167] 트리의 지름  (0) 2021.04.04
[백준 1477] 휴게소 세우기  (0) 2021.04.01