BFS / DFS
Summary
최단 이동 횟수는 BFS, 연결 요소는 BFS/DFS, 모든 경우 탐색은 DFS/백트래킹이다.
재귀 깊이가 깊으면 Java에서는 반복 DFS를 우선 고려한다.
선택 기준
| 상황 | 추천 |
|---|---|
| 최단 거리 / 최소 이동 횟수 | BFS |
| 미로 탐색 | BFS |
| 연결 요소 개수 | BFS 또는 DFS |
| Flood Fill | BFS 또는 DFS |
| 백트래킹 / 모든 경우 탐색 | DFS |
| 재귀 깊이가 큼 | 반복 DFS 또는 BFS |
격자 BFS 거리 계산 검증 템플릿
import java.io.*;
import java.util.*;
public class Main {
static int n, m;
static char[][] board;
static int[][] dist;
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
board = new char[n][m];
dist = new int[n][m];
for (int i = 0; i < n; i++) {
board[i] = br.readLine().toCharArray();
Arrays.fill(dist[i], -1);
}
bfs(0, 0);
System.out.println(dist[n - 1][m - 1]);
}
static void bfs(int sx, int sy) {
if (board[sx][sy] == '1') return;
Queue<int[]> q = new ArrayDeque<>();
q.offer(new int[]{sx, sy});
dist[sx][sy] = 0;
while (!q.isEmpty()) {
int[] cur = q.poll();
int x = cur[0];
int y = cur[1];
for (int dir = 0; dir < 4; dir++) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (board[nx][ny] == '1') continue;
if (dist[nx][ny] != -1) continue;
dist[nx][ny] = dist[x][y] + 1;
q.offer(new int[]{nx, ny});
}
}
}
}반복 DFS 연결 요소 검증 템플릿
import java.io.*;
import java.util.*;
public class Main {
static int n, m;
static char[][] board;
static boolean[][] visited;
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
board = new char[n][m];
visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
board[i] = br.readLine().toCharArray();
}
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == '1' && !visited[i][j]) {
dfs(i, j);
count++;
}
}
}
System.out.println(count);
}
static void dfs(int sx, int sy) {
Deque<int[]> st = new ArrayDeque<>();
st.push(new int[]{sx, sy});
visited[sx][sy] = true;
while (!st.isEmpty()) {
int[] cur = st.pop();
int x = cur[0];
int y = cur[1];
for (int dir = 0; dir < 4; dir++) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (board[nx][ny] != '1') continue;
if (visited[nx][ny]) continue;
visited[nx][ny] = true;
st.push(new int[]{nx, ny});
}
}
}
}핵심 주의점
| 실수 | 주의 |
|---|---|
| visited를 poll 때 체크 | 큐에 중복으로 많이 들어갈 수 있음. 보통 offer 때 체크 |
| dist 초기값 0 | 방문 여부와 거리 0이 구분 안 됨. -1 추천 |
| 재귀 DFS | N이 크면 StackOverflow 위험 |
| 4방향/8방향 혼동 | 문제에서 대각선 허용 여부 확인 |
| 여러 시작점 BFS | 모든 시작점을 큐에 먼저 넣고 dist=0 |
엣지케이스
N = 1, M = 1
시작점이 이미 도착점
시작점/도착점이 벽
도달 불가능
여러 시작점
그래프가 끊김백지 복원
1. BFS에서 dist를 -1로 초기화하는 이유는?
2. visited는 언제 true로 바꾸는가?
3. 여러 시작점 BFS 초기화 방법은?
4. 재귀 DFS가 위험한 입력 크기는?