[ALGORITHM]BOJ2178-미로탐색
문제
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개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.
출력
첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.
예제 입력 1
4 6
101111
101010
101011
111011
예제 출력 1
15
예제 입력 2
4 6
110110
110110
111111
111101
예제 출력 2
9
예제 입력 3
2 25
1011101110111011101110111
1110111011101110111011101
예제 출력 3
38
예제 입력 4
7 7
1011111
1110001
1000001
1000001
1000001
1000001
1111111
예제 출력 4
13
나의 코드
BFS
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
public class Main {
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static int N, M;// 세로, 가로
static int[][] map;
static boolean[][] visited;
public static void main(String[] args) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] inputNM = bufferedReader.readLine().split(" ");
N = Integer.parseInt(inputNM[0]);
M = Integer.parseInt(inputNM[1]);
map = new int[N][M];
visited = new boolean[N][M];
for (int i = 0; i < N; i++) {
String[] input = bufferedReader.readLine().split("");
for (int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(input[j]);
}
}
BFS(0, 0);
System.out.println(map[N-1][M-1]);
}
public static void BFS(int x, int y) {
Queue<com.company.Point> queue = new LinkedList<>();
queue.add(new com.company.Point(x, y));
visited[y][x] = true;
while (!queue.isEmpty()){
com.company.Point curPoint = queue.poll();
if (curPoint.x == M-1 && curPoint.y == N-1) return;
for (int i = 0; i < 4; i++){
int nextX = curPoint.x + dx[i];
int nextY = curPoint.y + dy[i];
if (nextX < 0 || nextY < 0 || M <= nextX || N <= nextY || visited[nextY][nextX] || map[nextY][nextX] == 0) continue;
visited[nextY][nextX] = true;
map[nextY][nextX] += map[curPoint.y][curPoint.x];
queue.add(new com.company.Point(nextX, nextY));
}
}
}
}
class Point{
int x;
int y;
Point(int x, int y){
this.x = x;
this.y = y;
}
}
DFS- 시간초과
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static int N, M;// 세로, 가로
static int[][] map;
static boolean[][] visited;
static int min = Integer.MAX_VALUE;
public static void main(String[] args) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] inputNM = bufferedReader.readLine().split(" ");
N = Integer.parseInt(inputNM[0]);
M = Integer.parseInt(inputNM[1]);
map = new int[N][M];
visited = new boolean[N][M];
for (int i = 0; i < N; i++) {
String[] input = bufferedReader.readLine().split("");
for (int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(input[j]);
}
}
DFS(0, 0, 0);
System.out.println(min);
}
public static void DFS(int x, int y, int count) {
visited[y][x] = true;
count++;
if (x == M - 1 && y == N - 1) {
min = Math.min(min, count);
return;
}
for (int i = 0; i < 4; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (nextX < 0 || nextY < 0 || M <= nextX || N <= nextY || visited[nextY][nextX] || map[nextY][nextX] == 0 || min < count)
continue;
visited[nextY][nextX] = true;
DFS(nextX, nextY, count);
visited[nextY][nextX] = false;
}
}
}
-
BFS는 너비우선 탐색으로 범위를 넓혀가면서 탐색을 한다. 그렇기 때문에 목적지 닿는 곳을 최소로 찾을수 있을 것이다. 그리고 찾으면 종료된다.
-
하지만 DFS는 깊이우선 탐색으로 한가지 경로를 잡으면 끝까지 가고, 그 다음 경로로 끝가지 가고 이런식이다. 그렇기 때문에 최소값을 찾기 위해서 모든 경로를 다 본 다음에 최소값을 찾아내야 한다.
-
‼️ 따라서 최단 경로에는 BFS가 더 적합하다 ‼️
- 위 DFS경우 조건을 걸어서 최단 거리 없을거 같은 경우를 제외시켜주는 ? 그런걸 나중에 고민해서 더 짜봐야겠다.
-
BFS일 경우 탐색 길을 누적하는 것으로 하였다. 그러면 목적지에 최단경로의 값이 들어가 있을 것이다.
//입력1 101111 101010 101011 111011 //출력1 1 0 9 10 11 12 2 0 8 0 12 0 3 0 7 0 13 14 4 5 6 0 14 15 //입력2 110110 110110 111111 111101 //출력2 1 2 0 8 9 0 2 3 0 7 8 0 3 4 5 6 7 8 4 5 6 7 0 9
보기 어렵지만 아무튼 이런식으로 !
느낀점
BFS에 비해 DFS는 구현하기 더 간단하지만 시간초과 문제를 고려해야한다. 쓸모없는 탐색이 많을 수록 시간초과가 잘 된다. 그런 점에서 이 문제는 BFS가 더 적절했던거 같다. 문제를 보고 먼저 BFS/DFS중 어떤게 더 적합한 방법인지 고민하고 코드를 짜도록 해야겠다. 🧐이 문제를 통해 최단거리에는 BFS가 더 적합하다는 것을 알게되었다. 🧐
- 문제: https://www.acmicpc.net/problem/2178
- 저장소:
- DFS: https://github.com/yoo-chaewon/HELLO_JAVA/blob/master/Algorithm/1.BOJ/Q_2178_미로탐색_0114_DFS.java
- BFS: https://github.com/yoo-chaewon/HELLO_JAVA/blob/master/Algorithm/1.BOJ/Q_2178_미로탐색_0114_BFS.java