[1068] 트리

HeeSeong·2021년 10월 2일
0

백준

목록 보기
77/79
post-thumbnail

🔗 문제 링크

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


🔍 문제 설명


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

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

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



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



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


⚠️ 제한사항


  • N은 50보다 작거나 같은 자연수이다.

  • 만약 부모가 없다면 (루트) -1이 주어진다.



🗝 풀이 (언어 : Java)


DFS로 트리를 탐색하는 문제이다. 제거해야할 서브트리의 부모 노드와 연결된 간선을 제거하고 루트부터 전체 그래프를 탐색해서 리프노드를 카운트하는 방법으로 풀었다. 다른 방법은 DP 개념을 이용하여 각 노드마다 가지고 있는 리프노드 수를 임의의 배열에 따로 저장해서 위로 올라가면서 부모 노드에서 합해주는 방식으로 푸는 방법도 있다. 다음에는 이러한 방식을 응용해보자.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

class Main {
    private static int leafCount = 0;

    private static void findLeaf(int node, int parent, List<Integer>[] graph) {
        for (int son : graph[node]) {
            if (son == parent) {
                if (graph[node].size() == 1) // 부모 노드만 연결된 리프노드 경우
                    leafCount++;
                continue;
            }
            findLeaf(son, node, graph);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine()), root = 0;
        List<Integer>[] graph = new ArrayList[n];
        int[] whereParent = new int[n];
        // 그래프 리스트 초기화
        for (int i = 0; i < n; i++)
            graph[i] = new ArrayList<>();
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        for (int i = 0; i < n; i++) {
            int parent = Integer.parseInt(st.nextToken());
            whereParent[i] = parent;
            if (parent == -1) // 루트 노드 위치 저장
                root = i;
            else
                graph[parent].add(i); // 해당 노드를 부모 노드에 양방향 연결(루트노드는 -1이므로 제외)
            graph[i].add(parent);
        }
        int target = Integer.parseInt(br.readLine());
        br.close();
        if (target != root) { // 제거할 트리가 루트인 경우 답은 0
            List<Integer> par = graph[whereParent[target]];
            for (int i = 0; i < par.size(); i++) { // 지울 타겟의 루트 노드에서 타겟 노드 제거
                if (par.get(i) == target)
                    par.remove(i);
            }
            findLeaf(root, -1, graph); // 삭제할 서브트리를 제거후 전체트리 탐색
        }
        System.out.print(leafCount);
    }
}
profile
끊임없이 성장하고 싶은 개발자

0개의 댓글