BFS / DFS

Summary

최단 이동 횟수는 BFS, 연결 요소는 BFS/DFS, 모든 경우 탐색은 DFS/백트래킹이다.
재귀 깊이가 깊으면 Java에서는 반복 DFS를 우선 고려한다.


선택 기준

상황추천
최단 거리 / 최소 이동 횟수BFS
미로 탐색BFS
연결 요소 개수BFS 또는 DFS
Flood FillBFS 또는 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 추천
재귀 DFSN이 크면 StackOverflow 위험
4방향/8방향 혼동문제에서 대각선 허용 여부 확인
여러 시작점 BFS모든 시작점을 큐에 먼저 넣고 dist=0

엣지케이스

N = 1, M = 1
시작점이 이미 도착점
시작점/도착점이 벽
도달 불가능
여러 시작점
그래프가 끊김

백지 복원

1. BFS에서 dist를 -1로 초기화하는 이유는?
2. visited는 언제 true로 바꾸는가?
3. 여러 시작점 BFS 초기화 방법은?
4. 재귀 DFS가 위험한 입력 크기는?