[프로그래머스] 게임 맵 최단거리(level2, DFS)
DFS 개념 참고
https://gayeon-l.tistory.com/490
DFS 개념
DFS (Depth-First Search) 개념DFS(Depth-First Search, 깊이 우선 탐색)는 그래프나 트리의 모든 노드를 탐색하는 알고리즘이다.이 알고리즘은 한 노드에서 시작하여 가능한 깊이까지 탐색한 후 더 이상 탐색
gayeon-l.tistory.com
문제 설명
ROR 게임은 두 팀으로 나누어서 진행하며, 상대 팀 진영을 먼저 파괴하면 이기는 게임입니다.
따라서, 각 팀은 상대 팀 진영에 최대한 빨리 도착하는 것이 유리합니다.
지금부터 당신은 한 팀의 팀원이 되어 게임을 진행하려고 합니다. 다음은 5 x 5 크기의 맵에,
당신의 캐릭터가 (행: 1, 열: 1) 위치에 있고, 상대 팀 진영은 (행: 5, 열: 5) 위치에 있는 경우의 예시입니다.
위 그림에서 검은색 부분은 벽으로 막혀있어 갈 수 없는 길이며, 흰색 부분은 갈 수 있는 길입니다. 캐릭터가 움직일 때는 동, 서, 남, 북 방향으로 한 칸씩 이동하며, 게임 맵을 벗어난 길은 갈 수 없습니다.
아래 예시는 캐릭터가 상대 팀 진영으로 가는 두 가지 방법을 나타내고 있습니다.
- 첫 번째 방법은 11개의 칸을 지나서 상대 팀 진영에 도착했습니다.
두 번째 방법은 15개의 칸을 지나서 상대팀 진영에 도착했습니다.
위 예시에서는 첫 번째 방법보다 더 빠르게 상대팀 진영에 도착하는 방법은 없으므로, 이 방법이 상대 팀 진영으로 가는 가장 빠른 방법입니다.
만약, 상대 팀이 자신의 팀 진영 주위에 벽을 세워두었다면 상대 팀 진영에 도착하지 못할 수도 있습니다. 예를 들어, 다음과 같은 경우에 당신의 캐릭터는 상대 팀 진영에 도착할 수 없습니다.
게임 맵의 상태 maps가 매개변수로 주어질 때, 캐릭터가 상대 팀 진영에 도착하기 위해서 지나가야 하는 칸의 개수의 최솟값을 return 하도록 solution 함수를 완성해주세요. 단, 상대 팀 진영에 도착할 수 없을 때는 -1을 return 해주세요.
제한사항
- maps는 n x m 크기의 게임 맵의 상태가 들어있는 2차원 배열로, n과 m은 각각 1 이상 100 이하의 자연수입니다.
- n과 m은 서로 같을 수도, 다를 수도 있지만, n과 m이 모두 1인 경우는 입력으로 주어지지 않습니다.
- maps는 0과 1로만 이루어져 있으며, 0은 벽이 있는 자리, 1은 벽이 없는 자리를 나타냅니다.
- 처음에 캐릭터는 게임 맵의 좌측 상단인 (1, 1) 위치에 있으며, 상대방 진영은 게임 맵의 우측 하단인 (n, m) 위치에 있습니다.
입출력 예
maps | answer |
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,1],[0,0,0,0,1]] | 11 |
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,0],[0,0,0,0,1]] | -1 |
입출력 예 설명
입출력 예 #1
주어진 데이터는 다음과 같습니다.
캐릭터가 적 팀의 진영까지 이동하는 가장 빠른 길은 다음 그림과 같습니다.
따라서 총 11칸을 캐릭터가 지나갔으므로 11을 return 하면 됩니다.
입출력 예 #2
문제의 예시와 같으며, 상대 팀 진영에 도달할 방법이 없습니다. 따라서 -1을 return 합니다.
DFS
문제 풀이
class Solution {
static int n, m;
static int[] dx = {-1, 0, 1, 0}; // 상, 우, 하, 좌
static int[] dy = {0, 1, 0, -1};
static int minPath = Integer.MAX_VALUE; // 최단 거리 (초기값 무한으로 설정)
public int solution(int[][] maps) {
n = maps.length; // 맵의 세로 크기
m = maps[0].length; // 맵의 가로 크기
// 방문 여부를 추적하는 배열
boolean[][] visited = new boolean[n][m];
// DFS를 이용한 경로 탐색 시작 (시작점은 (0, 0))
dfs(0, 0, maps, visited, 1); // 시작 지점은 1칸부터 시작
// 목표 지점에 도달할 수 없다면 -1 반환
return minPath == Integer.MAX_VALUE ? -1 : minPath;
}
// DFS 함수 (현재 위치 x, y와 지나온 칸 수를 인자로 받음)
public void dfs(int x, int y, int[][] maps, boolean[][] visited, int steps) {
// 목표 지점에 도달한 경우
if (x == n - 1 && y == m - 1) {
minPath = Math.min(minPath, steps); // 최단 경로 갱신
return;
}
// 만약 현재까지 탐색한 경로가 이미 최단 경로보다 길면 더 이상 진행하지 않음
if (steps >= minPath) return;
// 현재 위치를 방문 처리
visited[x][y] = true;
// 4방향으로 탐색 (상, 우, 하, 좌)
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 범위 체크 및 갈 수 있는 곳인지 확인
if (nx >= 0 && nx < n && ny >= 0 && ny < m
&& maps[nx][ny] == 1 && !visited[nx][ny]) {
// 해당 칸으로 이동하여 재귀 호출
dfs(nx, ny, maps, visited, steps + 1);
}
}
// 탐색이 끝난 후, 해당 칸을 다시 방문하지 않은 것으로 처리
visited[x][y] = false;
}
}
DFS로 풀려고 하면 자꾸 타임오버가 발생해서 효율성 부분에서 통과하지 못한다.
타임오버가 발생하는 이유는 DFS는 보통 재귀 함수를 사용하는데 해당 문제의 경우 이때 시간이 오래걸리기 때문이다.
DFS의 모든 경로를 스택을 사용해서 탐색하는 것보다 BFS로 큐를 사용해 너비우선으로 탐색하는 방법이 소요 시간에 있어서 더욱 효율적이다.
BFS 문제 풀이 링크
https://gayeon-l.tistory.com/505
[프로그래머스] 게임 맵 최단거리(level2, BFS)
BFS 개념 참고https://gayeon-l.tistory.com/491 BFS 개념BFS: 너비 우선 탐색가까운 노드부터 우선적으로 탐색하는 알고리즘보통 그래프 탐색에 사용두 노드 사이의 최단 경로 또는 임의의 경로를 찾을 때
gayeon-l.tistory.com