백준

1043 - 거짓말 (Java)

whiporithm 2024. 9. 21. 23:03

 


 

문제

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

 

풀이

[* 먼저 말하자면 이 문제는 union - find 로 푸는게 정설인 거 같다.]

 

이 문제의 요점은, 진실을 알고 있는 사람을 통해 건너건너 거짓말쟁이에게 진실이 전해질 수 있다는 점이다.

 

만약 진실을 알고 있는 사람이 1이라고 가정했을 때,

 

파티 1 : 1 2

파티 2 : 2 3

파티 3 : 3 4

 

이런식으로 이루어져 있을 때

 

2번이 1번을 통해 진실을 듣게 된다. 다음에 3번은 2번을 통해 들을 수 있고, 4번은 3번을 통해서 들을 수 있다.  (파티의 순서는 상관없다)

 

따라서 건너건너까지 진실을 알고 있는 사람과의 파티에 엮여있는지 확인할 필요가 있다.

 

나는 스텝을 나눠서 코드를 구현했다.

 

1. 우선 진실을 아는 사람들을 저장한다.

 

2. 같이 파티를 한 사람을 저장한다.

  - 이 때 Map<Integer, List<Integer>> 형태로, Key는 사람번호를 저장하고 리스트에는 같이 파티를 한 사람들을 저장했다.

 

3. 파티를 다시 확인하면서, 2번에서 저장한 자료구조를 활용하여 진실을 아는 사람과 연결되어 있는 사람이 있는지 확인한다.

 

이 스텝으로 문제를 해결했다.

 

결국 건너건너 진실을 아는 사람과 연결되어 있는가? 가 포인트이고, 나는 이 부분을 bfs 를 활용해서 풀었다.

 

 

 

코드

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

public class Main {

    public void solution() throws Exception {
        int answer = 0;
        // 파티에 참가하되, 그 내부에 진실을 아는 사람이 있는지를 판단해야한다.

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        // n : 사람의 수, m : 파티의 수
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        // 진실을 아는 사람은 Set에 저장한다.
        st = new StringTokenizer(br.readLine());
        st.nextToken();

        Set<Integer> truth = new HashSet<>();
        while (st.hasMoreTokens()) {
            truth.add(Integer.parseInt(st.nextToken()));
        }

        // 파티를 List로 입력 받는다.
        List<ArrayList<Integer>> partys = new ArrayList<>();

        for (int i = 0; i < m; i++) {
            ArrayList<Integer> party = new ArrayList<>();
            st = new StringTokenizer(br.readLine());
            st.nextToken();

            while (st.hasMoreTokens()) {
                party.add(Integer.parseInt(st.nextToken()));
            }
            partys.add(party);
        }


        // 파티 구성원을 그래프 형태로 세팅한다.
        Map<Integer, HashSet<Integer>> relationship = new HashMap<>();
        for (int i = 1; i <= n; i++) {
            relationship.put(i, new HashSet<>());
        }

        // O(n) = 250,000
        for (ArrayList<Integer> party : partys) {
            int len = party.size();
            for (int i = 0; i < len - 1; i++) {
                for (int j = i + 1; j < len; j++) {
                    relationship.get(party.get(i)).add(party.get(j));
                    relationship.get(party.get(j)).add(party.get(i));
                }
            }
        }


        // 파티 구성원을 모두 순회하면서 BFS 를 수행하다가 진실을 아는 사람을 만날 경우에는
        for (ArrayList<Integer> party : partys) {

            boolean possible = true;

            // 배열을 돌면서 모두 queue에 넣어주고, 방문 처리를 해준다.
            Deque<Integer> queue = new ArrayDeque<>();
            boolean[] visited = new boolean[n + 1];

            for (Integer i : party) {
                queue.addLast(i);
                visited[i] = true;
            }

            while (!queue.isEmpty()) {
                int target = queue.removeFirst();

                // 만약 진실을 아는 사람이 포함되어 있다면
                if(truth.contains(target)){
                    possible = false;
                    break;
                }

                // target과 연관되어 있는 사람들
                HashSet<Integer> knownPeople = relationship.get(target);

                // 해당 사람이 방문되지 않은 사람이라면, bfs를 수행한다.
                for (Integer knownPerson : knownPeople) {
                    if(!visited[knownPerson]){
                        queue.addLast(knownPerson);
                        visited[knownPerson] = true;
                    }
                }

            }

            if(possible) answer++;
        }

        System.out.println(answer);
    }

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }
}

 

후기

 

제한이 적어서 될 거라 생각했고, 단번에 풀긴했는데.. 정설은 union find 였다. 왜 이생각을 못했을까 ,,

'백준' 카테고리의 다른 글

2116 - 주사위 쌓기 (Java)  (1) 2024.09.23
15662 - 톱니바퀴(2)  (0) 2024.09.23
1374 - 강의실 (Java)  (1) 2024.09.19
5567 - 결혼식 (Java)  (0) 2024.09.03
2564 - 경비원 (Java)  (0) 2024.08.30