알고리즘
[백준] 2178-미로 탐색 (Java)
주인 완
2024. 12. 23. 01:01
https://www.acmicpc.net/problem/2178
문제
구현 방식
(0,0) → (m,n) 으로 이동하는데 얼마나 많은 블럭을 이동해야하는지 판단하는 것이 관건인 문제이다.
입력 처리
- 숫자가 공백 없이 주어지므로, 문자열 입력 후 개행(\n)을 기준으로 분리한다.
- 각 줄에서 불필요한 ‘0’을 제거한 뒤 정수 형태로 변환하여 미로를 표현하는 2차원 배열에 저장한다.
BFS를 위한 자료구조
- 큐(Queue)를 생성하여 BFS 로직을 구현한다.
- 방문 여부와 이동 거리를 동시에 관리하기 위해 check라는 2차원 배열을 사용한다.
- check[y][x]에는 '(y, x)까지 이동하는 데 필요한 거리'를 저장한다.
- 이전 위치의 check 값에 1을 더한 값을 현재 위치에 대입함으로써 거리를 갱신한다.
로직
- 우선 check[0][0]을 방문한 상태(1)로 만들어 준 후, Point 객체를 이용하여 (y, x) 좌표를 입력한 후 큐에 해당 좌표를 삽입한다.
- 이후 while루프를 큐의 크기가 0이 될 때까지 돌리면서, (y, x) 좌표를 상하좌우로 이동하는 배열을 이용하여 (ny, nx)에 대입하여 이동하도록 한다.
- 이 때 (y, x)는 현재 좌표를, (ny, nx)는 다음 이동할 좌표를 의미한다.
- 이 때 오버플로우 및 언더플로우, 갈 수 없는 곳을 방지하는 if문을 만든다.
만약 해당 조건에 (ny, nx)가 하나라도 걸릴 시, continue 구문을 통해 해당 좌표는 넘어간다.
또한 check 배열이 0이 아니면(방문한 곳) 마찬가지로 continue 구문을 통해 해당 좌표는 넘어간다. - 이후 현재 좌표(y, x)를 큐에서 제거하고, for문이 끝나면(같은 레벨 탐색 종료) 다시 첫 값부터 제거하여 반복하도록 한다.
BFS에서 조건문 생성시의 주의사항
오버플로우/언더플로우(배열 범위를 벗어나는 경우)와 이동 불가능한 지역을 구분해야 한다.
if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] == 0) {
continue;
}
여기서 중요한 점은 '오버플로우/언더플로우 체크'가 먼저 이루어져야 한다는 것이다.
- ny < 0 || ny >= n || nx < 0 || nx >= m : 배열 범위 확인
- arr[ny][nx] == 0 : 이동할 수 없는 지역(벽 등) 판단
만약 방문한 적이 있는 곳(check[ny][nx] != 0)이면, 다시 방문할 필요가 없으므로 continue 구문을 통해 해당 좌표는 넘어간다.
정답 코드
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static Queue<Point> queue = new LinkedList<>();
static int[][] arr, check;
static int[] dy = {-1, 0, 1, 0};
static int[] dx = {0, 1, 0, -1};
static int ny, nx, n, m;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
arr = new int[n][m];
check = new int[n][m];
for (int i = 0; i < n; i++) {
String s = br.readLine();
for (int j = 0; j < m; j++) {
arr[i][j] = s.charAt(j) - '0';
}
}
check[0][0] = 1;
queue.offer(new Point(0, 0));
while (!queue.isEmpty()) {
Point p = queue.poll();
int y = p.x;
int x = p.y;
for (int i = 0; i < 4; i++) {
ny = y + dy[i];
nx = x + dx[i];
if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] == 0) {
continue;
}
if (check[ny][nx] != 0) {
continue;
}
check[ny][nx] = check[y][x] + 1;
queue.offer(new Point(ny, nx));
}
}
System.out.println(check[n - 1][m - 1]);
}
}