플밍/문제풀이

[Java] BOJ2178, 백준 - 미로 탐색

kkap999 2021. 9. 3. 18:16
728x90

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

시간 제한 메모리 제한 제출 정답 맞은 사람 정답 비율
1 초  192MB 99380 40148 25619 39.046%

문제

N×M크기의 배열로 표현되는 미로가 있다.

1 0 1 1 1 1
1 0 1 0 1 0
1 0 1 0 1 1
1 1 1 0 1 1

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.

위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

 

입력

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

 

출력

첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

 

<풀이>

처음에는 DFS로 풀려고했는데, 재귀 방식으로 풀려면 최단 경로를 찾아야하기 때문에 사실상 모든 경로를 다 탐색해야했다. DFS가 아니라 브루트포스가 되어버림

그래서 DFS로는 못풀고, BFS로 풀어야 했다.

BFS를 사용하면 한 지점에서 연결된 모든 정점으로 이동할 때, 한 칸씩 이동되기 때문에 결국 BFS를 몇 번 수행했는지만 알면 어떠한 칸에 도달하기까지의 최단 거리를 손쉽게 구해낼 수 있다.

 

상하좌우로 이동할 수 있기 때문에 상하좌우의 이동방향을 배열에 저장하여 손쉽게 탐색을 이어나갈 수 있도록 하였다.

	private static int[][] moving = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };

그리고 이동하는 점의 좌표와 해당 정점에 오기까지 BFS를 몇 번 수행했는지 저장해야했기 때문에, BFS를 수행할 큐의 타입을 클래스를 만들어 지정해주었다.

class Coordinate {
	int x = 0;
	int y = 0;
	int cnt = 0;

	Coordinate(int x, int y, int cnt) {
		this.x = x;
		this.y = y;
		this.cnt = cnt;
	}
}

이를 이용하여 BFS를 수행하면 된다.

 

소스코드

import java.io.*;
import java.util.*;

public class Main {

	private static int[][] moving = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };

	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());

		int[][] maze = new int[n][m];
		boolean[][] check = new boolean[n][m];

		// 미로 입력
		for (int i = 0; i < n; i++) {
			String s = br.readLine();
			for (int j = 0; j < m; j++) {
				maze[i][j] = s.charAt(j) - '0';
			}
		}

		// 미로 탐색, 첫 번째 점(0,0)에서 시작
		// 최단 거리 알고리즘이기 때문에 BFS를 이용
		Queue<Coordinate> queue = new LinkedList<Coordinate>();

		queue.add(new Coordinate(0, 0, 1));
		check[0][0] = true;
		while (!queue.isEmpty()) {
			// 이어진 점이 있는지 검사
			int x = queue.peek().x;
			int y = queue.peek().y;

			if (x == m - 1 && y == n - 1) {
				System.out.println(queue.peek().cnt);
				break;
			}

			for (int i = 0; i < 4; i++) {
				int nx = x + moving[i][0];
				int ny = y + moving[i][1];
				if (nx >= 0 && ny >= 0 && nx < m && ny < n) {
					if (maze[ny][nx] == 1 && !check[ny][nx]) {
						check[ny][nx] = true;
						queue.add(new Coordinate(nx, ny, queue.peek().cnt + 1));
					}
				}
			}
			queue.poll();
		}
	}
}

class Coordinate {
	int x = 0;
	int y = 0;
	int cnt = 0;

	Coordinate(int x, int y, int cnt) {
		this.x = x;
		this.y = y;
		this.cnt = cnt;
	}
}

 

총평: 최단거리 알고리즘은 BFS를 이용하면 쉽게 해결할 수 있다!