Algorithm & Data Structures/BOJ
b4803. ํธ๋ฆฌ
Geisha
2025. 4. 28. 17:52
https://www.acmicpc.net/problem/4803
๐ ์๋ฐ(Java)๋ก ํธ๋ ํธ๋ฆฌ - ๋ฐฑ์ค 4803 ๐ณ
์ฌ์ดํด ํ์ง + ์ฐ๊ฒฐ ์์(ํธ๋ฆฌ) ๊ฐ์ ๊ตฌํ๊ธฐ (Union-Find)
๐ ๋ฌธ์ ๊ฐ์
๋ฐฑ์ค 4803 - ํธ๋ฆฌ ๋ฌธ์ ๋,
- ์ฃผ์ด์ง ๊ทธ๋ํ์์ ์ฌ์ดํด์ด ์๋ ์ฐ๊ฒฐ ์์(ํธ๋ฆฌ)๋ฅผ ์ฐพ์์ผ ํ๋ ๋ฌธ์ ์ ๋๋ค.
- ํ๋์ ๊ทธ๋ํ ์์ ์ฌ๋ฌ ๊ฐ์ ํธ๋ฆฌ๊ฐ ์์ ์ ์์ผ๋ฉฐ,
- ์ฌ์ดํด์ด ์๋ ์ฐ๊ฒฐ ์์๋ ํธ๋ฆฌ๋ก ์ทจ๊ธํ์ง ์์ต๋๋ค.
๐ก ์์ ์ ๋ ฅ
6 3
1 2
2 3
5 6
6 5
2 1
0 0
๐ก ์์ ์ถ๋ ฅ
Case 1: A forest of 2 trees.
Case 2: No trees.
๐ ์๊ณ ๋ฆฌ์ฆ ์ ๊ทผ ๋ฐฉ์
์ด ๋ฌธ์ ๋ ์ ํ์ ์ธ Union-Find(Disjoint Set) ์๊ณ ๋ฆฌ์ฆ์
โ ์ฌ์ดํด ๊ฐ์ง๋ฅผ ๋ง๋ถ์ด๋ ๋ฌธ์ ์ ๋๋ค.
๐ ํต์ฌ ์๋ฃ๊ตฌ์กฐ
- p[i] : i๋ฒ ๋ ธ๋์ ๋ถ๋ชจ๋ฅผ ๋ํ๋ ๋๋ค.
- ์ฌ์ดํด์ด ๋ฐ์ํ ์งํฉ์ ๋ฃจํธ๋ฅผ 0์ผ๋ก ๋ง๋ค์ด์ ํธ๋ฆฌ๊ฐ ์๋์ ํ์ํฉ๋๋ค.
๐ ์ด๊ธฐํ
p = new int[N+1];
for (int i = 0; i <= N; i++)
p[i] = i;
โ ๊ฐ ๋ ธ๋์ ๋ถ๋ชจ๋ฅผ ์๊ธฐ ์์ ์ผ๋ก ์ด๊ธฐํํฉ๋๋ค.
๐ ๊ฐ์ ์ฐ๊ฒฐ (Union ์ฐ์ฐ)
int pa = find(a);
int pb = find(b);
if (pa > pb) {
int temp = pa;
pa = pb;
pb = temp;
}
if (pa == pb) {
p[pa] = 0; // ์ฌ์ดํด ๋ฐ์
}
else {
p[pb] = p[pa]; // ๋ฃจํธ ๋ณํฉ
}
โ ๋ ๋ ธ๋์ ๋ฃจํธ๋ฅผ ์ฐพ์ ํฉ์นฉ๋๋ค.
โ ์ด๋ฏธ ๊ฐ์ ์งํฉ์ด๋ผ๋ฉด, ์ฌ์ดํด์ด ๋ฐ์ํ ๊ฒ์ผ๋ก ๋ณด๊ณ ๋ฃจํธ๋ฅผ 0์ผ๋ก ์ค์ ํฉ๋๋ค.
๐ ๋ถ๋ชจ ์ฐพ๊ธฐ (Find ์ฐ์ฐ)
static int find(int a){
if(p[a] == a) return a;
return p[a] = find(p[a]);
}
โ ๊ฒฝ๋ก ์์ถ(Path Compression)์ ์ ์ฉํ์ฌ find ์๋๋ฅผ ์ต์ ํํฉ๋๋ค.
๐ ์ต์ข ํธ๋ฆฌ ๊ฐ์ ์ธ๊ธฐ
HashSet<Integer> set = new HashSet<>();
for (int i = 1; i <= N; i++) {
int tree = find(i);
if (tree > 0)
set.add(tree);
}
โ ๋ฃจํธ๊ฐ 0์ด ์๋ ๋ ธ๋๋ค์ ์งํฉ์ ์ถ๊ฐํด
โ ํธ๋ฆฌ์ ๊ฐ์๋ฅผ ์ผ๋ค.
๐ ์ถ๋ ฅ ํฌ๋งท
if (set.size() == 1)
sb.append("There is one tree.\n");
else if (set.isEmpty())
sb.append("No trees.\n");
else
sb.append("A forest of " + set.size() + " trees.\n");
โ ํธ๋ฆฌ ๊ฐ์์ ๋ฐ๋ผ ๋ง๋ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
โ ์ ๋ฆฌ
ํต์ฌ ํฌ์ธํธ | ์ค๋ช |
์ฌ์ดํด์ด ์๊ธฐ๋ฉด ๋ฃจํธ๋ฅผ 0์ผ๋ก ์ธํ | ์ฌ์ดํด ๋ฐ์ ์ ํด๋น ์ฐ๊ฒฐ ์์๋ฅผ ํธ๋ฆฌ๋ก ์ทจ๊ธํ์ง ์๊ธฐ |
find()์์ ๊ฒฝ๋ก ์์ถ | ์๊ฐ ๋ณต์ก๋ ์ต์ ํ (๊ฑฐ์ O(1)) |
set์ผ๋ก ๊ณ ์ ํ ๋ฃจํธ๋ง ์นด์ดํธ | ํธ๋ฆฌ์ ๊ฐ์๋ฅผ ์ ํํ ๊ตฌํ๊ธฐ ์ํจ |
๐ฅ ์ฝ๋ ์ ์ฒด (์ ๋ฆฌ)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;
public class b4803 {
static int N, M;
static int[] p;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int cnt = 1;
while (true) {
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
if (N == 0 && M == 0) break;
p = new int[N+1];
for (int i = 0; i <= N; i++)
p[i] = i;
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
union(a, b);
}
sb.append("Case ").append(cnt++).append(": ");
HashSet<Integer> set = new HashSet<>();
for (int i = 1; i <= N; i++) {
int tree = find(i);
if (tree > 0)
set.add(tree);
}
if (set.size() == 1)
sb.append("There is one tree.\n");
else if (set.isEmpty())
sb.append("No trees.\n");
else
sb.append("A forest of ").append(set.size()).append(" trees.\n");
}
System.out.println(sb);
}
static int find(int a) {
if (p[a] == a) return a;
return p[a] = find(p[a]);
}
static void union(int a, int b) {
int pa = find(a);
int pb = find(b);
if (pa > pb) {
int temp = pa;
pa = pb;
pb = temp;
}
if (pa == pb) {
p[pa] = 0;
} else {
p[pb] = p[pa];
}
}
}