미로 찾기
그리드의 크기 : N x N (N-1, N-1)
현재 위치에서 출구까지 가는 경로가 있으려면
1) 현재 위치가 출구이거나
2) 이웃한 셀들 중 하나에서 현재 위치를 다시 지나지 않고 출구까지 가는 경로가 있거나
STEP 1. 현재 위치에서 출구까지 가는 경로가 있는지 없는지 확인하는 코드
즉, 이 알고리즘의 핵심 부분을 설명하는 Decisioin Problem을 작성한다.
if (x,y) is the exit
return true;
-> 현재 위치가 출구이면 경로가 있다.
for each neighbouring cell (x',y') of (x,y) do
if (x',y') is on the pathway
if findPath(x',y')
return true;
-> 현재 위치와 근접한 각각의 셀들 중에서 벽을 제외한 셀들에 대해 출구까지 가는 경로가 있는지 recursive하게 확인한다.
= 현재 위치와 근접한 셀들 중 벽이 아닌 길이라면 출구까지의 경로를 반복적으로 탐색한다.
return false;
-> 위 코드에서 true값이 반환되지 않고 아래 코드로 내려왔다 = 현재 위치와 인접한 각각의 셀들 중에서 출구까지 가는 경로가 없다.
STEP 2. 해당 알고리즘이 무한루프에 빠지지 않는지 검사한다.
이 경우에는 findPath(x,y)가 인접 셀인 (x',y')를 호출했을 때 findPath(x',y')
옮겨온 셀 (x',y') 입장에서는 (x,y)가 자신에게 인접한 셀이 되어 findPath(x,y)를 호출해
findPath(x,y)는 findPath(x',y')를 계속 호출하고, findPath(x',y')는 findPath(x,y)를 계속 호출하는 무한 루프에 빠진다.
이런 일은 어떻게 방지할 수 있을까?
이미 가본 위치와 가보지 않은 위치를 구별해서 가보지 않은 셀들을 대상으로 경로를 탐색한다.
예를 들어, 이미 방문한 셀에는 visited = 1이라고 표시를 하고
이웃한 셀들 중 아직 방문하지 않은 셀 (visited = 0)만 호출할 수 있도록 하면 무한루프 문제를 막을 수 있다는 것이다.
현재 위치 (x,y)에서 인접한 셀인 (x',y')에 대한 탐색을 시작할 때 먼저 "이 셀은 방문했다!!"고 visitied=1처럼 표시해두고 다음 단계로 넘어간다. 그 후, 다른 셀에서 (x',y')를 탐색하려고 할 경우, visitied 값을 확인하여 방문했다고 표시되어 있는 셀이라면 탐색을 생략해서 무한루프에 빠지지 않게 한다.
따라서, STEP 1 코드와 합치게 되면
인접한 셀들 중, 1) 벽이 아닌 통로이고 2) 방문한 적이 없는 셀에 대해서만 출구까지의 경로를 찾으면 된다.
혹은 반대로,
아예 함수의 첫 부분에서 1) 통로가 아닌 벽이고 2) 방문한 적이 있는 셀 이라면 경로를 탐색할 조건에 부합하지 않다고 판단하여 false를 반환해버리게 구현할 수도 있다.
=> 위 코드가 최종적인 sudo code로 이 방식으로 구현할 예정
STEP 3. 구현
미로 탐색 경로
코드
import java.util.Scanner;
public class example {
private static int N=8;
private static int[][] maze = {
{0,0,0,0,0,0,0,1},
{0,1,1,0,1,1,0,1},
{0,0,0,1,0,0,0,1},
{0,1,0,0,1,1,0,0},
{0,1,1,1,0,0,1,1},
{0,1,0,0,0,1,0,1},
{0,0,0,1,0,0,0,1},
{0,1,1,1,0,1,0,0}
};
private static final int PATHWAY_COLOUR = 0;
private static final int WALL_COLOUR = 1;
private static final int BLOCKED_COLOUR = 2; // 방문해서 PATH_COLOUR이었다가 경로가 아니라고 판단된 셀
private static final int PATH_COLOUR = 3; // 방문했고 아직 꽝인지 출구까지 경로인지 모르는 셀
public static boolean findMazePath(int x, int y) {
if (x<0 || y<0 || x>=N || y>=N) return false; // 그리드 벗어나는 위치라면 false
else if (maze[x][y] != PATHWAY_COLOUR) return false; // 방문했던 셀이라면 false
else if(x==N-1 && y==N-1) { // 도착 위치(최종 경로)를 찾았다면 true
maze[x][y]=PATH_COLOUR;
return true;
}
else { // 인접 셀을 통해 경로 찾기
maze[x][y] = PATH_COLOUR; // 방문했지만 아직 꽝인지 아닌지 몰라! 그렇지만 재탐색은 안돼!
if(findMazePath(x,y+1) || findMazePath(x+1, y) || findMazePath(x,y-1) || findMazePath(x-1,y))
return true; // 인접한 셀들 중 경로가 있다면 그 방향으로 계속 탐색을 반복해
maze[x][y] = BLOCKED_COLOUR; // 방문했지만 꽝이야 그쪽엔 길 없어
return false; // 그 경로로는 탐색 그만해 -> 다른 경로로 탐색해보자
}
}
public static void printMaze() {
for (int i = 0; i < maze.length; i++) {
for (int j = 0; j < maze[i].length; j++) {
System.out.print(maze[i][j] + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
printMaze();
findMazePath(0,0);
System.out.println();
printMaze();
}
}
결과
근접 셀들을 방문할 때 PATH_COLOUR=3로 "방문한 셀이야"라고 표시해 놓고 길이 없으면 BLOCKED-COLOUR=2로 변경한다.
따라서 2라고 표시된 곳들은 이미 방문했지만 (N-1, N-1)까지 경로가 없는 셀들이다. (말그대로 "막힌 길")
3으로 표시된 셀들을 이어나가보면 미로 탐색 경로 사진에서 찾았던 경로와 일치하는 출구까지의 경로를 찾을 수 있다.
'Algorithm > Inflearn' 카테고리의 다른 글
[Inflearn] 자바 알고리즘 문제풀이 #02-09 9. 격자판 최대합 (0) | 2022.11.21 |
---|---|
[Inflearn] 자바 알고리즘 문제풀이 #02-08 8. 등수구하기 (0) | 2022.11.21 |
[Inflearn] 자바 알고리즘 문제풀이 #02-07 7. 점수계산 (0) | 2022.11.16 |
[Inflearn] 영리한 프로그래밍을 위한 알고리즘 - 순환 (Recursion) 의 개념과 기본 예제 3 (0) | 2022.11.15 |
[Inflearn] 자바 알고리즘 문제풀이 #02-06 6. 뒤집은 소수 (0) | 2022.11.15 |