본문 바로가기

Hub Algorithm/위상 정렬

[BOJ] 백준 5021 : 왕위 계승 (java)

728x90

🧪 5021 왕위 계승


난이도 : 🌟 골드 4
유형 : 위상 정렬

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

 

📝 문제


유토피아의 왕이 사망했다. 왕은 자손을 남기지 않고 사망했기 때문에, 왕위를 계승할 사람을 지목하지 않았다. 왕실 귀족은 왕위를 주장하기 시작했다. 유토피아의 법에는 왕의 계승자가 없는 경우에, 나라를 세운 사람과 혈통이 가까운 사람이 유토피아를 통치한다는 조항이 있다.

나라를 세운 사람과 혈통이 가장 가까운 사람은 그의 자손이 아닌 사람과 피가 덜 섞인 사람이다. 모든 사람은 아버지의 혈통과 어머니의 혈통을 반 씩 받게 된다. 나라를 세운 사람의 자식은 1/2 왕족이며, 그 아들이 왕족이 아닌 사람과 결혼한 경우에는 아들의 자식은 1/4 왕족이 된다.

가장 나라를 세운 사람과 혈통이 가까운 사람을 찾는 프로그램을 작성하시오. 

 

 

입력

 

첫째 줄에 N과 M이 주어진다. (2 ≤ N, M ≤ 50)

둘째 줄에 유토피아를 세운 사람의 이름이 주어진다.

다음 N개 줄에는 가족 정보가 주어진다. 정보는 이름 세 개로 이루어져 있고, 공백으로 구분되어져 있다. 첫 번째 이름은 자식의 이름이고, 뒤의 두 이름은 부모의 이름이다.

다음 M개 줄에는 왕위를 계승받기를 주장하는 사람의 이름이 한 줄에 하나씩 주어진다.

모든 이름은 1~10글자이며, 알파벳 소문자로만 이루어져 있다. 나라를 세운 사람이 왕위를 계승하는 경우나, 누군가의 자식인 경우는 없다. 

 

출력

 

첫째 줄에 유토피아를 세운 사람과 가장 혈통이 가까운 사람의 이름을 출력한다. 항상 답이 유일한 경우만 입력으로 주어진다.

문제에 주어지는 가족 관계는 성별, 나이를 고려하지 않고 만들었기 때문에, 실제로는 말이 안되는 경우가 나올 수도 있다. 하지만, 모든 자식의 부모는 유일하며, 다시 자식이 부모의 부모가 되는 경우도 없다. 또, 한 사람이 여러 명의 자식이 될 수 도 없다.

 

🚧  주의할 점


  1. bloodTree.put(rootNode, 1d); 의 위치가 for문보다 전에 나오는 경우 rootNode의 값이 -1로 갱신되기 때문에 for문의 뒤에 둬야한다.

🧐 핵심 로직 


1) 자식과 부모의 관계를 저장할 familyTree 맵과 혈통의 정도를 나타내는 bloodTree 맵을 만들어준다.

 

2) 자식과 부모의 경우는 -1로 초기화 해주고, rootNode의 경우는 1로 초기화 해준다.

 

3) dfsAll 메서드를 활용해서 위상정렬을 해준다.

 

4) dfs 메서드 내부에서는 부모의 혈통을 활용해서 자식의 혈통을 구해 반환한다.

    4 - 1 ) 이때, bloodTree에 이미 -1이 아닌 다른 값이 저장되어 있다면 반환한다.

    4 - 2 ) 또한, familyTree가 null 즉, 왕족이 아니고 부모가 없는 경우 0으로 값을 넣고 반환한다.

 

5) main 메서드로 돌아와 successor와 competitor의 혈통값을 비교해 혈통이 더 큰 경우를 출력한다.

 

💻 최종 코드 (128 ms)


import java.io.*;
import java.util.*;

public class Main {

    static int n, m;
    static HashMap<String, ArrayList<String>> familyTree;
    static HashMap<String, Double> bloodTree;
    public static void main(String[] args) throws IOException {

//        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedReader br = new BufferedReader(new FileReader("input.txt"));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        String rootNode = br.readLine();
        familyTree = new HashMap<>();
        bloodTree = new HashMap<>();

        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            String son = st.nextToken();

            if (familyTree.get(son) == null) {
                familyTree.put(son, new ArrayList<>());
            }

            String father = st.nextToken();
            familyTree.get(son).add(father);
            String mother = st.nextToken();
            familyTree.get(son).add(mother);

            bloodTree.put(son, -1d);
            bloodTree.put(father, -1d);
            bloodTree.put(mother, -1d);
        }

        bloodTree.put(rootNode, 1d);

        dfsAll();

//        for (String name : bloodTree.keySet()) {
//            System.out.println(String.format("name : %s\t\tvalue : %f", name,
//                    bloodTree.get(name)));
//        }

        String successor = br.readLine();
        for (int i = 1; i < m; i++) {
            String competitor = br.readLine();

            if (bloodTree.getOrDefault(successor, 0d) < bloodTree.getOrDefault(competitor, 0d)) {
                successor = competitor;
            }
        }

        System.out.println(successor);

        br.close();
    }

    private static void dfsAll() {

        for (String name : bloodTree.keySet()) {
            dfs(name);
        }
    }

    private static double dfs(String name) {

        if (bloodTree.get(name) != -1) {
            return bloodTree.get(name);
        }

        // 부모가 존재하지 않는 즉, 왕족이 아닌 0의 경우
        if (familyTree.get(name) == null) {
            bloodTree.put(name, 0d);
            return bloodTree.get(name);
        }

        double fatherBlood = dfs(familyTree.get(name).get(0));
        double motherBlood = dfs(familyTree.get(name).get(1));

        bloodTree.put(name, (fatherBlood + motherBlood) / 2);

        return bloodTree.get(name);
    }
}

'Hub Algorithm > 위상 정렬' 카테고리의 다른 글

[BOJ] 백준 1005 : ACM Craft (java)  (3) 2024.07.23
[BOJ] 백준 1516 : 게임 개발 (java)  (2) 2024.02.09