CodingTest/Java

BOJ_1043 : 거짓말

Soom_1n 2023. 6. 9. 20:39

 

πŸ‘‰ 문제링크

 

1043번: 거짓말

μ§€λ―Όμ΄λŠ” νŒŒν‹°μ— κ°€μ„œ 이야기 ν•˜λŠ” 것을 μ’‹μ•„ν•œλ‹€. νŒŒν‹°μ— 갈 λ•Œλ§ˆλ‹€, μ§€λ―Όμ΄λŠ” 지민이가 κ°€μž₯ μ’‹μ•„ν•˜λŠ” 이야기λ₯Ό ν•œλ‹€. μ§€λ―Όμ΄λŠ” κ·Έ 이야기λ₯Ό 말할 λ•Œ, μžˆλŠ” κ·ΈλŒ€λ‘œ μ§„μ‹€λ‘œ λ§ν•˜κ±°λ‚˜ μ—„μ²­λ‚˜κ²Œ

www.acmicpc.net



πŸ”Έ 문제 뢄석 πŸ”Έ

  • 문제 λ‚΄μš©
    • Nλͺ…μ˜ μ‚¬λžŒκ³Ό M개의 νŒŒν‹°κ°€ μžˆλ‹€.
    • 진싀을 μ•„λŠ” μ‚¬λžŒμ΄ μ°Έμ—¬ν•œ νŒŒν‹°μ—μ„œλŠ” μ§„μ‹€λ§Œ 말해야 ν•œλ‹€.
    • 진싀을 λ§ν•œ νŒŒν‹°μ— 있던 μ‚¬λžŒλ“€λ„ 진싀을 μ•„λŠ” μ‚¬λžŒμ΄ λœλ‹€.
    • 거짓을 말할 수 μžˆλŠ” νŒŒν‹°μ˜ 수λ₯Ό 좜λ ₯ν•œλ‹€.
  • 풀이 μ „λž΅
    • 같은 νŒŒν‹° μ°Έκ°€μžλ₯Ό μ—°κ²°ν•΄μ•Ό ν•œλ‹€.
    • 각 νŒŒν‹°λ³„ μ°Έκ°€μž List와 개인 별 μ°Έκ°€ νŒŒν‹° Listλ₯Ό λ§Œλ“ λ‹€.
    • BFS둜 진싀을 λ§ν•œ νŒŒν‹°μ™€ 진싀을 μ•Œκ²Œλœ μ‚¬λžŒλ“€μ„ μΆ”κ°€ν•΄ λ‚˜κ°„λ‹€.
    • 진싀을 λ§ν•˜μ§€ μ•Šμ€ νŒŒν‹°μ˜ 수λ₯Ό 좜λ ₯ν•œλ‹€.
  • 2024.04.22 μΆ”κ°€
    • 기쑴에 BFSλ₯Ό 톡해 ν’€μ΄ν–ˆμ§€λ§Œ, 뢄리 μ§‘ν•©μœΌλ‘œλ„ 풀이할 수 μžˆμ–΄μ„œ λ‹€μ‹œ ν’€μ–΄λ³΄μ•˜λ‹€.
    • 같은 νŒŒν‹°μ— μ°Έκ°€ν•œ 인원듀을 union μ—°μ‚°μœΌλ‘œ 같은 집합에 λ„£μ–΄μ€€λ‹€.
    • νŒŒν‹°μ˜ 집합에 진싀을 μ•„λŠ” μ‚¬λžŒλ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•ŠμœΌλ©΄ μΉ΄μš΄νŠΈν•œλ‹€.

πŸ”Έ μ½”λ“œ πŸ”Έ

import java.io.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        // Input
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        st = new StringTokenizer(br.readLine());

        ArrayList<Integer>[] person = new ArrayList[N + 1];
        ArrayList<Integer>[] party = new ArrayList[M];
        Boolean[] know = new Boolean[N + 1];
        Boolean[] visited = new Boolean[M];

        for (int i = 1; i <= N; i++) {
            person[i] = new ArrayList<>();
            know[i] = false;
        }

        for (int i = 0; i < M; i++) {
            party[i] = new ArrayList<>();
            visited[i] = false;
        }

        for (int i = 0; i < M; i++) {
            StringTokenizer st1 = new StringTokenizer(br.readLine());
            int person_cnt = Integer.parseInt(st1.nextToken());
            for (int j = 0; j < person_cnt; j++) {
                int ps = Integer.parseInt(st1.nextToken());
                party[i].add(ps); // νŒŒν‹° 별 μ°Έκ°€μž 기둝
                person[ps].add(i); // 개인 별 μ°Έκ°€ νŒŒν‹° 기둝
            }
        }

        // BFS
        int cnt = M;
        Queue<Integer> que = new ArrayDeque<>();

        // 처음 λΆ€ν„° 진싀을 μ•„λŠ” μ‚¬λžŒλ“€ 큐 μ΄ˆκΈ°ν™”
        int know_cnt = Integer.parseInt(st.nextToken());
        for (int i = 0; i < know_cnt; i++) {
            int k = Integer.parseInt(st.nextToken());
            know[k] = true;
            que.add(k);
        }

        while (!que.isEmpty()) {
            int np = que.poll();
            for (int pt : person[np]) {
                if (!visited[pt]) {
                    visited[pt] = true;
                    cnt--;
                    for (int ps : party[pt]) {
                        if (!know[ps]) {
                            know[ps] = true;
                            que.add(ps);
                        }
                    }
                }
            }
        }

        // Output
        bw.write(Integer.toString(cnt));
        bw.flush();
    }
}

πŸ”Έ μ½”λ“œ 해석 πŸ”Έ

  • 개인 별 μ°Έκ°€ν•œ νŒŒν‹° 번호, νŒŒν‹° 별 μ°Έκ°€μž 번호λ₯Ό ArrayList에 μž…λ ₯λ°›λŠ”λ‹€.
  • μ²˜μŒλΆ€ν„° 진싀을 μ•„λŠ” μ‚¬λžŒλ“€μ€ 큐의 μ΄ˆκΈ°κ°’μœΌλ‘œ λ„£λŠ”λ‹€.
    • 진싀을 μ•„λŠ” μ‚¬λžŒ λͺ…단 know 배열을 true둜 λ°”κΎΌλ‹€.
  • 큐가 빌 λ•ŒκΉŒμ§€ λ°˜λ³΅ν•˜λ©° 진싀을 μ•„λŠ” μ‚¬λžŒλ“€μ„ μΆ”κ°€ν•œλ‹€.
    • ν˜„μž¬ μ°Έκ°€μžκ°€ μ°Έμ—¬ν•œ νŒŒν‹° λͺ©λ‘μ„ μˆœνšŒν•œλ‹€.
    • 아직 κ±°μ§“ νŒŒν‹°μ˜€μœΌλ©΄, 진싀을 λ“€μ—ˆμœΌλ―€λ‘œ visitedλ₯Ό true둜 λ°”κΎΈκ³ ,
      κ±°μ§“ νŒŒν‹°μ˜ 수 cntλ₯Ό -1ν•œλ‹€.
    • ν•΄λ‹Ή νŒŒν‹°μ— μ†Œμ† 된 μ°Έκ°€μžλ“€ 쀑 진싀을 μ•Œκ²Œλœ μ‚¬λžŒλ“€μ„ 큐에 λ„£κ³  knowλŠ” true둜 λ°”κΏ”μ€€λ‹€.
  • cntλ₯Ό 좜λ ₯ν•œλ‹€.

 

πŸ”Έ 뢄리 μ§‘ν•© μ½”λ“œ πŸ”Έ

import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    private static int[] parent;

    public static void main(String[] args) throws IOException {
        // Input
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        st = new StringTokenizer(br.readLine());
        int known = Integer.parseInt(st.nextToken());

        if (known == 0) {
            bw.write(Integer.toString(M));
            bw.flush();
            return;
        }

        parent = new int[N + 1];
        for (int i = 1; i <= N; i++) {
            parent[i] = i;
        }

        // Disjoint Set

        int[] knowns = new int[known]; // 사싀을 μ•„λŠ” μ‚¬λžŒλ“€
        ArrayList<Integer>[] list = new ArrayList[M];

        for (int i = 0; i < known; i++) {
            knowns[i] = Integer.parseInt(st.nextToken());
        }

        for (int i = 0; i < M; i++) {
            list[i] = new ArrayList<>();
            st = new StringTokenizer(br.readLine());

            int people = Integer.parseInt(st.nextToken());

            int first = Integer.parseInt(st.nextToken());
            list[i].add(first);
            first = find(first);

            for (int j = 1; j < people; j++) {
                int member = Integer.parseInt(st.nextToken());
                list[i].add(member);
                union(first, member);
            }
        }

        int cnt = 0;
        for (int i = 0; i < M; i++) {
            boolean flag = true;
            int pp = find(list[i].get(0));
            for (int j = 0; j < known; j++) {
                if (find(pp) == find(knowns[j])) {
                    flag = false;
                    break;
                }
            }
            if (flag) cnt++;
        }

        // Output
        bw.write(Integer.toString(cnt));
        bw.flush();
    }

    private static void union(int a, int b) {
        int ap = find(a);
        int bp = find(b);

        if (ap != bp) parent[ap] = bp;
    }

    private static int find(int a) {
        if (parent[a] == a) return a;
        return parent[a] = find(parent[a]);
    }
}

πŸ”Έ end πŸ”Έ

  • μ†Œμ†(μ—°κ²°) 정보λ₯Ό ArrayList둜 μ €μž₯ν•œ λ’€ BFSλ₯Ό 톡해 μ‰½κ²Œ 풀이할 수 μžˆμ—ˆλ‹€.
  • 문제 νƒœκ·Έμ— 뢄리 μ§‘ν•©(Disjoint Set) 이 있길래 ν•΄λ‹Ή 풀이λ₯Ό μ°Ύμ•„λ³΄μ•˜λ‹€. (μ°Έκ³  ν¬μŠ€νŒ…)
    • μ—°κ²° λ˜μ–΄ μžˆλŠ” μ°Έκ°€μžλ“€μ„ 같은 집합에 ν¬ν•¨λ˜μ–΄μžˆλ‹€κ³  보고, μ§‘ν•©μ˜ ν•œ μ›μ†Œκ°€ 진싀을 μ•Œκ²Œ 되면 ν•΄λ‹Ή μ§‘ν•© λͺ¨λ‘ μ§„μŠ¬μ„ μ•„λŠ” λ°©μ‹μ˜ ν’€μ΄μ—ˆλ‹€.
    • 일반적인 Union-Find와 λ‹€λ₯΄κ²Œ, μ§‘ν•© λ‚΄ μ›μ†Œ λͺ¨λ‘ 진싀을 μ•Œκ²Œ λ˜λŠ”μ§€ 확인이 ν•„μš”ν–ˆκ³ , κ±°μ§“ νŒŒν‹°μ˜ μΉ΄μš΄νŠΈκ°€ ν•„μš”ν•΄μ„œ 좔가적인 아이디어가 ν•„μš”ν•œ 것 κ°™λ‹€.
  • 문제 뢄석과 풀이 κ³„νšμ„ 적어가며 ν’€μ΄ν–ˆλ‹€.

728x90