Post

BOJ 17090 미로 탈출하기

BOJ 17090 미로 탈출하기

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

문제

크기가 N×M인 미로가 있고, 미로는 크기가 1×1인 칸으로 나누어져 있다. 미로의 각 칸에는 문자가 하나 적혀있는데, 적혀있는 문자에 따라서 다른 칸으로 이동할 수 있다.

어떤 칸(r, c)에 적힌 문자가

  • U인 경우에는 (r-1, c)로 이동해야 한다.
  • R인 경우에는 (r, c+1)로 이동해야 한다.
  • D인 경우에는 (r+1, c)로 이동해야 한다.
  • L인 경우에는 (r, c-1)로 이동해야 한다.

미로에서 탈출 가능한 칸의 수를 계산해보자. 탈출 가능한 칸이란, 그 칸에서 이동을 시작해서 칸에 적힌대로 이동했을 때, 미로의 경계 밖으로 이동하게 되는 칸을 의미한다.


입력

첫째 줄에 미로의 크기 N, M(3 ≤ N, M ≤ 500)이 주어진다. 둘째 줄부터 N개의 줄에는 미로의 각 칸에 적힌 문자가 주어진다.


출력

첫째 줄에 탈출 가능한 칸의 수를 출력한다.


예제 입력 1

3 3
DDD
DDD
DDD

예제 출력 1

9

예제 입력 2

3 3
DDR
DLU
LLL

예제 출력 2

9

… 이하 예제 생략


코드

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static int N, M, answer = 0;
    static int[][] map;
    static boolean[][] visited;
    static int[] dirRow = {-1, 0, 0, 1}, dirCol = {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());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        map = new int[N][M];
        visited = new boolean[N][M];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                switch (br.read()) {
                    case 'U': map[i][j] = 0; break;
                    case 'R': map[i][j] = 1; break;
                    case 'L': map[i][j] = 2; break;
                    case 'D': map[i][j] = 3; break;
                }
            }
            br.readLine();
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                checkEscapable(i, j);
            }
        }
        System.out.println(answer);
    }
    
    static void checkEscapable(int row, int col) {
        // 검사하는 블록이 이미 탈출 가능하다고 증명된 경우, 증명하지 않고 answer++
        if (map[row][col] == Integer.MAX_VALUE) {
            answer++;
            return;
        }
        
        // 검사하는 블록이 이미 탈출 불가능하다고 증명된 경우, 증명하지 않고 검사 종료
        if (map[row][col] == Integer.MIN_VALUE) return;
        
        // dfs로 탈출 가능 여부 검사
        dfs(row, col);
    }

    static boolean dfs(int row, int col) {
        visited[row][col] = true; // 무한루프에 빠지지 않기 위해 visited 체크
        // 검사 위치의 알파벳에 따라 이동할 위치 계산
        int newRow = row + dirRow[map[row][col]], newCol = col + dirCol[map[row][col]];
        // 이동할 위치가 탈출인(맵 밖인) 여부 조사
        boolean isEscaped = newRow < 0 || newRow >= N || newCol < 0 || newCol >= M;
        boolean result;
        // 이동할 위치가 탈출이거나 이미 탈출 가능하다고 증명된 경우,
        // 이동할 위치가 무한루프에 빠지는 위치거나 이미 탈출 불가능하다고 증명된 경우,
        // 이동할 위치의 탈출 가능 여부가 아직 검사되지 않은 경우로 나눠서 해결한다.
        if (isEscaped || map[newRow][newCol] == Integer.MAX_VALUE) {
            answer++;
            result = true;
        } else if (visited[newRow][newCol] || map[newRow][newCol] == Integer.MIN_VALUE) {
            result = false;
        } else {
            result = dfs(newRow, newCol);
        }
        if(result) map[row][col] = Integer.MAX_VALUE; // 검사 위치가 탈출 가능한 경우 해당 위치를 MAX_VALUE로 초기화
        else map[row][col] = Integer.MIN_VALUE; // 검사 위치가 탈출 불가능한 경우 해당 위치를 MIN_VALUE로 초기화
        return result; // 검사 결과를 반환해 이전 위치의 검사 결과를 알림
    }
}
This post is licensed under CC BY 4.0 by the author.