Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- half adder
- Algorithm
- soc 설계
- hc-sr04
- uart 통신
- verilog
- Pspice
- gpio
- atmega 128a
- Recursion
- LED
- behavioral modeling
- Edge Detector
- test bench
- structural modeling
- KEYPAD
- DHT11
- java
- BASYS3
- ATMEGA128A
- prescaling
- stop watch
- Linked List
- vivado
- pwm
- i2c 통신
- dataflow modeling
- ring counter
- FND
- D Flip Flop
Archives
- Today
- Total
거북이처럼 천천히
Java - 미로 찾기 본문
1. 문제 (미로 찾기)
- 파란색은 벽, 흰 색은 이동할 수 있는 통로를 의미
- 입구는 (0, 0), 출구는 (N-1, N-1)이며, 입구에서 시작해서 출구로 빠져나올 수 있도록 경로를 찾는다.
2. 생각(Recursion Thinking)
본 문제를 Recursion(재귀)를 이용하여 풀기 위해서 Recursion 하게 생각하였다. Recursion Thinking을 하면 현재 상황을 다음과 같이 나누어서 생각할 수 있다.
If 현재 위치에서 출구까지 갈 수 있는 경로가 존재하려면
- 현재 위치가 출구 이거나
- 이웃한 셀들(= 현재 위치에서의 동서남북 셀)중에서 현재 위치를 지나지 않고, 출구까지 가는 경로가 있어야 한다.
2.1. Write the code by recursion.
Recursion Thinking을 이용하여 코드를 작성하면 다음과 같이 작성할 수 있다.
boolean findPath(x, y) {
// ** 확인 1. 현재 셀(x, y)이 출구에 위치해 있는가?
if(x, y) is the exit.
return true;
else
// ** 확인 2. 현재 셀에 이웃한 최대 4개의 셀에 대해서 확인
for each neighbouring cell (x', y') of (x, y) do
if findPath(x', y')
return true;
return false;
}
하지만, 위 코드에서 문제점이 발생하였는데, 바로 Recursion case가 base case에 수렴하지 않아 무한루프에 빠지게 된 것이다. 즉, 다시 말해 (x, y)에서 이웃한 셀인 (x', y')으로 이동한 다음, 다시 또 (x', y')에서 지나온 (x, y)로 이동하는 것이다.
이로 인해 두 셀만 서로 왔다갔다하여 무한 루프에 빠지게 되는 것이다. 이를 해결하기 위해 "지나온 셀은 무시하고, 나머지 이웃한 셀에 대해서만 Recursion을 실행한다."는 조건이 필요하다.
방법 1)
boolean findPath(x, y)
// ** 1. 현재 셀이 출구인지
if (x, y) is the exit
return true;
else
// ** 2. 현재 셀에 이웃한 셀들에 대해서 재귀
// * 2.1. 현재의 셀(x, y)을 마킹한다.
mark (x, y) as a visited cell;
for each neighbouring cell (x', y') of (x, y) do
// * 2.2. 이웃한 셀(x', y')이 지나온 셀인지 확인
if(x', y') is on the pathway and not visited
if findPath(x', y')
return true;
return false;
방법 2)
boolean findPath(x, y)
// 1. 현재 셀이 벽이거나 지나온 셀인지
if (x, y) is on the wall or a visited cell.
return false;
// 2. 현재 셀이 출구인지
else if (x, y) is the exit
return true;
// 3. 이웃한 셀(x', y')에 대해서 재귀 실행
else
mark (x, y) as a visited cell.
for each neighbouring cell (x', y') of (x, y) do
if findPath(x', y')
return true;
return false;
3. 풀이 및 코드 분석
import java.util.Scanner;
public class FindMazePath {
// *** Initialization
private static final int PATHWAY_COLOR = 0; // white
private static final int WALL_COLOR = 1; // blue
private static final int ENTRANCE_COLOR = 2; // yellow
private static final int EXIT_COLOR = 3; // yellow
private static final int BLOCKED_COLOR = 4; // red
private static final int PATH_COLOR = 5; // green
private static Scanner scan = new Scanner(System.in);
private static int[][] maze;
private static int size;
public static void main(String[] args) {
size = 0;
// *** Get the size of maze.
while(true) {
System.out.print("Enter size of maze: ");
size = scan.nextInt();
if(size<=0)
System.out.println("The size is less than zero.");
else
break;
}
// *** Maze initialization.
maze = new int[size][size];
// *** Get maze information.
for(int j=0; j<size; j++) {
System.out.print("Enter element: ");
for(int i=0; i<size; i++) {
maze[j][i] = scan.nextInt();
}
}
// *** Get entrance & exit.
int[] entrance = getCoordinate("entrance");
int[] exit = getCoordinate("exit");
maze[entrance[0]][entrance[1]] = ENTRANCE_COLOR;
maze[exit[0]][exit[1]] = EXIT_COLOR;
// *** Print the maze.
printMaze(maze);
// *** Find a path way of maze.
if(findPath(entrance[0], entrance[1], exit))
printMaze(maze);
else
System.out.println("\n There is no exit to escape the maze.");
}
// ** Print maze array.
private static void printMaze(int[][] maze) {
System.out.println("\nMaze Array: ");
for(int j=0; j<maze.length; j++) {
for(int i=0; i<maze[0].length; i++) {
if(maze[j][i]==PATHWAY_COLOR)
System.out.print(" □");
else if(maze[j][i]==WALL_COLOR)
System.out.print(" ■");
else if(maze[j][i]==ENTRANCE_COLOR)
System.out.print(" ☆");
else if(maze[j][i]==EXIT_COLOR)
System.out.print(" ★");
else if(maze[j][i]==PATH_COLOR)
System.out.print(" v");
else
System.out.print(" X");
}
System.out.println();
}
}
// ** Get coordinate.
private static int[] getCoordinate(String contents) {
int[] coordinate = new int[2];
while(true) {
System.out.printf("Enter %s: ", contents);
for(int i=0; i<2; i++)
coordinate[i] = scan.nextInt();
if(coordinate[0]<0 || coordinate[0]>=size || coordinate[1]<0 || coordinate[1]>=size)
System.out.printf("The %f is out of maze.\n", contents);
else if(maze[coordinate[0]][coordinate[1]]==1)
System.out.print("The point is the wall.\n");
else
break;
}
return coordinate;
}
// ** Find the path for exit.
private static boolean findPath(int x, int y, int[] exit) {
if(x<0 || x>=size || y<0 || y>=size)
return false;
else if(maze[x][y]!=PATHWAY_COLOR && maze[x][y]!=ENTRANCE_COLOR && maze[x][y]!=EXIT_COLOR)
return false;
else if(x==exit[0] && y==exit[1]) {
maze[x][y] = PATH_COLOR;
return true;
}else {
maze[x][y] = PATH_COLOR;
if(findPath(x, y+1, exit) || findPath(x+1, y, exit)
|| findPath(x, y-1, exit) || findPath(x-1, y, exit))
return true;
}
maze[x][y] = BLOCKED_COLOR;
return false;
}
}
4. 메모
- 첫 번째 방법은 Recursion을 하기 전에 해당 셀이 이미 지나올 셀인지를 확인하지만, 두 번째 방법은 해당 셀이 지나온 셀인지 확인할 필요 없이 무조건 Recursion하기 때문에 첫 번째 방법이 두 번째 방법보다 시간적으로나 효율적으로나 더 좋다고 할 수 있다.
'Algorithm > 알고리즘 문제 풀이' 카테고리의 다른 글
Java - n Queen Problem (0) | 2022.10.09 |
---|---|
Java - Blob 넓이 구하기 (0) | 2022.10.06 |
Java - 싱글 연결리스트를 통해 다항식 계산 (0) | 2022.08.11 |
알고리즘 (6월 30일) (0) | 2022.06.30 |
알고리즘 (6월 29일) (0) | 2022.06.30 |