알고리즘/백준

2178번 - 미로 탐색

fleur75 2023. 6. 15. 13:55
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	
	static int[] dr = {-1, 1, 0, 0};
	static int[] dc = {0, 0, -1, 1};
	
	static class Point {
		int r;
		int c;
		
		Point(int r, int c) {
			this.r = r;
			this.c = c;
		}
	}
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());
		boolean[][] map = new boolean[N][M];
		String str;
		for(int i=0;i<N;i++) {
			str = br.readLine();
			for(int j=0;j<M;j++) {
				if(str.charAt(j) == '1') {
					map[i][j] = true;
				}
			}
		}
		int cnt = 0;
		LinkedList<Point> q = new LinkedList<>();
		q.offer(new Point(0, 0));
		map[0][0] = false;
		int nr, nc, size;
		loop:
		while(!q.isEmpty()) {
			size = q.size();
			cnt++;
			for(int k=0;k<size;k++) {
				Point cur = q.poll();
				if(cur.r == N-1 && cur.c == M-1) {
					break loop;
				}
				for(int i=0;i<4;i++) {
					nr = cur.r + dr[i];
					nc = cur.c + dc[i];
					if(nr < 0 || nc < 0 || nr >= N || nc >= M) {
						continue;
					}
					if(map[nr][nc]) {
						map[nr][nc] = false;
						q.offer(new Point(nr, nc));
					}
				}
			}
		}
		System.out.println(cnt);
		br.close();
	}
}

탐색 문제에서 보통 dfs와 bfs를 떠올리게 되는데 이 경우 최소 이동 횟수를 찾아야하기 때문에 bfs를 사용해서 for문의 반복 횟수를 구하는 것이 편리합니다.

 

이 때 일반적인 bfs가 아닌 for문을 돌고 난 이후의 size만큼 for문을 돌려 각 시행단계를 분리하는 방법을 사용해야 합니다. 이렇게 하면 맨 위의 for문을 작동시킬 때마다 cnt를 올려 이동 횟수를 셀 수 있습니다.

 

또한 여기서는 visited 배열을 사용하는 대신 맵을 지날 때 0으로 표시하는 방법으로 중복 이동을 제한했습니다. 이렇게 할 경우 최단거리로 접근하는 경로만이 살아남게 되어서 더 효율적으로 탐색할 수 있습니다.