
정점 1..N으로 이루어진 무방향 그래프가 주어졌을 때, 그래프가 몇 개의 “덩어리(연결된 그룹)”로 나뉘어 있는지 세는 문제다.
출력은 “연결 요소의 개수” 하나다.
DFS/BFS를 “몇 번 시작했는가”
이 문제는 한 번의 DFS/BFS로 끝나지 않는다.
따라서 정답은:
visited[i] == false인 정점을 발견할 때마다 탐색을 새로 시작하고, 그 시작 횟수를 센다.
이때 중요한 포인트는:
count++가 올라간다는 점이다.두 코드 모두 입력을 인접 리스트로 만든 뒤 탐색한다.
for (int i = 0; i < node + 1; i++) {
adjList.add(new ArrayList<>());
}
for (int i = 0; i < line; i++) {
int nodeA = ...
int nodeB = ...
adjList.get(nodeA).add(nodeB);
adjList.get(nodeB).add(nodeA);
}
for (List<Integer> list : adjList) {
list.sort(Comparator.naturalOrder());
}
11724는 “방문 순서 출력”이 없어서 정렬이 필수는 아니지만, 네 코드처럼 정렬해두면 디버깅할 때 인접 노드가 일정한 순서로 보여서 편하다.
DFS 버전의 핵심은 이 2개다.
for (int i = 1; i <= node; i++) {
if (!visited[i]) {
count++;
dfs(i);
}
}
여기서 count++는 새 연결 요소를 찾았다는 의미다.
static void dfs(int start) {
visited[start] = true;
for (int a : adjList.get(start)) {
if (!visited[a]){
dfs(a);
}
}
}
BFS 버전도 구조는 동일하다.
for (int i = 1; i <= node; i++) {
if (!visited[i]) {
count++;
bfs(i);
}
}
static void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
visited[start] = true;
while (!queue.isEmpty()){
int target= queue.poll();
for (int a : adjList.get(target)){
if(!visited[a]){
visited[a] = true;
queue.add(a);
}
}
}
}
포인트:
visited[a] = true를 큐에 넣는 시점에 해야 중복 삽입이 방지된다.import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
// 연결요소의 개수 - DFS
public class Main {
static int node;
static int line;
static List<List<Integer>> adjList = new ArrayList<>();
static boolean[] visited;
static int count = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
node = Integer.parseInt(st.nextToken());
line = Integer.parseInt(st.nextToken());
for (int i = 0; i < node + 1; i++) {
adjList.add(new ArrayList<>());
}
for (int i = 0; i < line; i++) {
StringTokenizer nodes = new StringTokenizer(br.readLine());
int nodeA = Integer.parseInt(nodes.nextToken());
int nodeB = Integer.parseInt(nodes.nextToken());
adjList.get(nodeA).add(nodeB);
adjList.get(nodeB).add(nodeA);
}
// 방문 순서는 상관 없지만, 기존 스타일 유지(정렬) [web:420]
for (List<Integer> list : adjList) {
list.sort(Comparator.naturalOrder());
}
visited = new boolean[node + 1];
for (int i = 1; i <= node; i++) {
if (!visited[i]) {
count++; // 새 연결요소 발견 [web:420]
dfs(i);
}
}
System.out.println(count);
}
static void dfs(int start) {
visited[start] = true;
for (int a : adjList.get(start)) {
if (!visited[a]) {
dfs(a);
}
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
// 연결요소의 개수 - BFS
public class Main {
static int node;
static int line;
static List<List<Integer>> adjList = new ArrayList<>();
static boolean[] visited;
static int count = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
node = Integer.parseInt(st.nextToken());
line = Integer.parseInt(st.nextToken());
for (int i = 0; i < node + 1; i++) {
adjList.add(new ArrayList<>());
}
for (int i = 0; i < line; i++) {
StringTokenizer nodes = new StringTokenizer(br.readLine());
int nodeA = Integer.parseInt(nodes.nextToken());
int nodeB = Integer.parseInt(nodes.nextToken());
adjList.get(nodeA).add(nodeB);
adjList.get(nodeB).add(nodeA);
}
// 방문 순서는 상관 없지만, 기존 스타일 유지(정렬) [web:284]
for (List<Integer> list : adjList) {
list.sort(Comparator.naturalOrder());
}
visited = new boolean[node + 1];
for (int i = 1; i <= node; i++) {
if (!visited[i]) {
count++; // 새 연결요소 발견 [web:284]
bfs(i);
}
}
System.out.println(count);
}
static void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
visited[start] = true;
while (!queue.isEmpty()) {
int target = queue.poll();
for (int a : adjList.get(target)) {
if (!visited[a]) {
visited[a] = true;
queue.add(a);
}
}
}
}
}
for (i=1..N)로 돌며 미방문 정점 발견 시 count++ 후 탐색 시작