넘치게 채우기

[BOJ] 1068 : 트리 본문

PS/BOJ

[BOJ] 1068 : 트리

riveroverflow 2023. 4. 19. 11:21
728x90
반응형

https://www.acmicpc.net/problem/1068

 

1068번: 트리

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

www.acmicpc.net

 

문제 유형 : DFS / 트리

solved.ac 난이도 : Gold V

 

문제

 

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

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

 

입력

 

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

 

출력

 

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

 

 

내가 생각해본 플랜

 

둘째 줄에 각 노드의 부모 정보가 들어있으므로, 역으로 부모에서 어느 자식으로 이어지는지에 대한 인접 리스트를 만들어준 다음,

제거할 노드의 연결 정보를 모두 없애서 서브트리까지 모두 없애고, 부모 노드에서도 자식 노드르 제거할 노드를 없앤다.

그 뒤, dfs를 통해서 리프노드의 개수를 구한다.

 

 

막혔던 부분과 해결

 

처음으로 만든 코드를 제출하자, 단 1초도 걸리지 않아 틀렸다고 나온다. 문제에서 기본 제공하는 테스트 케이스는 루트가 항상 0번이었지만, 이는 함정이다. 루트가 꼭 0번이라는 법이 없었다. 이를 알아채고, 루트를 구하는 함수를 만들고, 탐색을 0번부터가 아닌, 루트부터 시작시켜서 문제를 해결하였다.

 

 

코드(Python)

import sys
input = sys.stdin.readline
#입력값 받기와 기본 그래프 생성
n = int(input())
nodes = list(map(int, input().split()))
del_node = int(input())
graph = [[] for _ in range(n)]
#노드의 부모 정보들로 인접리스트 만들기
for i in range(n):
    if nodes[i] != -1:
        graph[nodes[i]].append(i)
#그래프에서 노드 제거하기
def delete(node):
    for i in graph[node]:
        delete(i)
    graph[node] = []
    for i in range(n):
        if node in graph[i]:
            graph[i].remove(node)

delete(del_node)

# 루트 노드를 찾는 함수
def find_root(nodes):
    return nodes.index(-1)

# 루트 노드부터 탐색하여 리프 노드의 개수를 계산
def count_leaf(graph, v):
    if len(graph[v]) == 0:
        return 1
    cnt = 0
    for i in graph[v]:
        cnt += count_leaf(graph, i)
    return cnt

#루트를 찾고, 루트를 없애는 문제라면 바로 0을 반환하게 함
root = find_root(nodes)
print(count_leaf(graph, root) if del_node != root else 0)

 

코드(C++)

#include <iostream>
#include <vector>

using namespace std;

int n, del_node;
vector<int> nodes, graph[50];

void delete_node(int node) {
    for(int i = 0; i < graph[node].size(); i++){
        int child = graph[node][i];
        delete_node(child);
    }
    graph[node].clear();
    for (int i = 0; i < n; i++){
        for (int j = 0; j < graph[i].size(); j++){
            if(graph[i][j] == node){
                graph[i].erase(graph[i].begin() + j);
                break;
            }
        }
    }
}

int find_root(const vector<int> &nodes){
    for (int i = 0; i < nodes.size(); i++){
        if(nodes[i] == -1){
            return i;
        }
    }
    return -1;
}

int count_leaf(const vector<int> graph[], int v){
    if(graph[v].empty()){
        return 1;
    }
    int cnt = 0;
    for(int i = 0; i < graph[v].size(); i++){
        cnt += count_leaf(graph, graph[v][i]);
    }
    return cnt;
}

int main(){
    cin >> n;
    nodes.resize(n);
    for (int i = 0; i < n; i++){
        cin >> nodes[i];
        if(nodes[i] != -1){
            graph[nodes[i]].push_back(i);
        }
    }
    cin >> del_node;
    delete_node(del_node);
    int root = find_root(nodes);
    if(del_node == root){
        cout << 0 << endl;
    }
    else{
        cout << count_leaf(graph, root) << endl;
    }
    return 0;
}
728x90
반응형

'PS > BOJ' 카테고리의 다른 글

[BOJ] 1328 : 고층 빌딩  (0) 2023.09.21
[BOJ] 16234 : 인구 이동  (0) 2023.09.19
[BOJ] 15686: 치킨 배달  (0) 2023.09.18
[BOJ] 12833 : XORXORXOR  (0) 2023.06.10
[BOJ] 2638 : 치즈  (0) 2023.04.24