문제
https://www.acmicpc.net/problem/1043
풀이
import java.io.*;
import java.util.*;
public class Main {
static int[] parent;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken()); // 사람의 수
int m = Integer.parseInt(st.nextToken()); // 파티의 수
parent = new int[n + 1];
for (int i = 1; i <= n; i++) {
parent[i] = i;
}
st = new StringTokenizer(br.readLine());
int people = Integer.parseInt(st.nextToken());
Set<Integer> known = new HashSet<>();
for (int i = 0; i < people; i++) {
known.add(Integer.parseInt(st.nextToken()));
}
List<List<Integer>> parties = new ArrayList<>();
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
int partySize = Integer.parseInt(st.nextToken());
List<Integer> party = new ArrayList<>();
for (int j = 0; j < partySize; j++) {
party.add(Integer.parseInt(st.nextToken()));
}
for (int j = 1; j < party.size(); j++) {
union(party.get(0), party.get(j));
}
parties.add(party);
}
// 진실을 아는 사람들의 루트 찾기 후 임시 리스트에 추가
Set<Integer> tempKnown = new HashSet<>();
for (int person : known) {
tempKnown.add(find(person)); // 임시 집합에 추가
}
known.addAll(tempKnown); // 임시 집합의 값을 한 번에 known에 추가
int count = 0;
for (List<Integer> party : parties) {
boolean canLie = true;
for (int person : party) {
if (known.contains(find(person))) {
canLie = false;
break;
}
}
if (canLie) count++;
}
System.out.println(count);
}
static int find(int x) {
if (parent[x] == x) return x;
return parent[x] = find(parent[x]);
}
static void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX;
}
}
}
find-union 알고리즘의 존재를 처음 알았다. 문제를 풀고나서 좀 다듬은 코드이다.
코드를 정리해보자면 다음과 같다.
먼저, 정답을 알고 있는 사람들의 집합을 만든다.
다음으로, 파티에 참석한 사람들을 하나의 부모를 가지게 묶어준다. 이 때, 파티 하나의 참가자 중 제일 앞 참가자를 기준 노드로 잡고 진행시킨다.
이렇게 하게 되면 union을 통해 하나의 파티에 대한 그룹이 형성된다.
만약 제일 앞 참가자의 노드가 다른 그룹에 대한 값을 갖고 있다면? 그 값까지 같이 묶이게 되는 것이다.
최종적으로 파티 참가자들을 순회하며 추적한 부모의 값이 진실을 알고 있는 사람인지 보면 되는 것이다.
'문제 풀이 > 백준' 카테고리의 다른 글
[백준]16967번. 배열 복원하기(JAVA) (0) | 2024.09.27 |
---|---|
[백준] 16918번. 봄버맨(JAVA) (0) | 2024.09.26 |
[백준] 17182번. 우주 탐사선 (0) | 2024.09.13 |
[백준] 14466번. 소가 길을 건너간 이유 6(JAVA) (1) | 2024.09.12 |
[백준] 18428번. 감시 피하기(JAVA) (0) | 2024.09.11 |