문제풀이/백준

[백준]20926: 얼음 미로 - JAVA

빈둥벤둥 2021. 7. 23. 17:23

[백준]20926: 얼음 미로

풀이

🪑 구현 + 다익스트라 문제이다. 

 

 

📝문제의 조건을 정리해보자.

  • 얼음 미로에서는 한 방향으로 이동시 바위나 출구를 만날때 까지 멈출 수 없다. 바깥은 절벽이다.
  • T: 상하좌우로 이동할 수 있다.
  • R: 통과할 수 없으며 부딪히면 멈춘다
  • H: 이곳에 빠지면 탈출할 수 없다.
  • E: 미로를 탈출하는 유일한 출구이다.
  • 각 위치마다 미끌시간이 존재하며 탈출할 수 있는 최단 미끌시간을 구한다.

 

 

🔧 다음과 같은 풀이를 생각해 주었다.

  1. 다익스트라를 사용한다.
  2. 한번 이동할 때 해당 방향으로 이동할 수 있는지 먼저 확인한다.
  3. 이동 가능하면 그 방향으로 갈 수 있는 곳까지 간다.
  4. 도착한 후 더 짧은 미끌시간을 계산해 준다.
  5. 도착 노드의 최단 미끌시간을 출력한다.

 

📌 처음엔 70 ~ 80프로 쯤에 틀렸었는데, INF 값을 Integer.MAX_VALUE로 변경해주니 통과되었다.

 

 

🔹 다익스트라를 사용한다.

- 최단 거리가 아닌, 최단 미끌시간을 갖는 경로를 계산해 주어야 하므로 단순 BFS로는 풀 수 없다. 다익스트라 알고리즘으로 최단 미끌시간을 저장해 주면서 탐색해 주어야 한다.

- 출발 지점인 T에서 시작하여 모든 노드로 가는 최단 경로를 탐색한다.

- 더 짧은 미끌시간을 가지는 순서대로 탐색을 한다.

 

🔹 한번 이동할 때 해당 방향으로 이동할 수 있는지 먼저 확인한다.

- 단순히 이동만 하는 것이 아니라 이동 하면서 이동 경로에 있는 값이 탐색에 필요하다. 

- 그러므로 일단 해당 방향으로 갈 수 있는지 먼저 확인 후, 갈 수 있을때만 경로에 있는 값을 계산해 준다.

 

🔹 이동 가능하면 그 방향으로 갈 수 잇는 곳까지 간다.

- 그 방향으로 갈 수 있는지 확인하기 위해 현재 위치에서 이동하는 방향으로의 비율을 늘려주며 탐색하였다.

- 가는 동안에 맵의 범위를 벗어나거나, H를 만난다면 갈 수 없는 방향이다.

- 가는 길에 바위를 만나면 그 전까지만 이동 가능한 위치가 된다.

- 가는 길에 출구를 만나면 출구까지 이동 가능한 위치가 된다.

 

🔹도착한 후 더 짧은 미끌시간을 계산해 준다.

- 원래의 미끌시간이랑 비교를 해서 현재 경로까지 이동하는 동안 추가되는 미끌시간과 지금까지 이동하며 추가된 미끌시간의 합 중에 더 작은 값을 저장해 준다.

 

🔹 도착 노드의 최단 미끌시간을 출력한다.

- 탐색할 수 있는 모든 경우가 끝나면 도착 노드의 최단 미끌시간을 출력해 준다.

 

코드

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import java.util.*;
 
public class Main {
 
    static char[][] board;
    static int[][] dist;
    static int w, h;
    static int[] dx = {010-1};
    static int[] dy = {-1010};
 
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
 
        //입력
        w = scan.nextInt();
        h = scan.nextInt();
        scan.nextLine();
 
        board = new char[h][w];
        int start_x = -1, start_y = -1;
        int end_x = -1, end_y = -1;
        for(int i = 0; i < h; i++) {
            String str = scan.nextLine();
            for(int j = 0; j < w; j++) {
                board[i][j] = str.charAt(j);
                if(board[i][j] == 'T') {
                    start_x = i;
                    start_y = j;
                } else if(board[i][j] == 'E') {
                    end_x = i;
                    end_y = j;
                }
            }
        }
        //입력 끝
 
        int INF = Integer.MAX_VALUE;
        dist = new int[h][w];
        for(int i = 0; i < h; i++) {
            Arrays.fill(dist[i], INF);
        }
 
        bfs(start_x, start_y);
        if(dist[end_x][end_y] == INF) System.out.println("-1");
        else System.out.println(dist[end_x][end_y]);
    }   
 
    public static void bfs(int x, int y) {
        PriorityQueue<Node> q = new PriorityQueue<>();
        boolean[][] visited = new boolean[h][w];
        q.offer(new Node(x, y, 0));
        dist[x][y] = 0;
 
        while(!q.isEmpty()) {
            Node current = q.poll();
        
            if(visited[current.x][current.y]) continue;
            visited[current.x][current.y] = true;
 
            for(int i = 0; i < 4; i++) {
                int go_ratio = can_go(i, current.x, current.y);
                if(go_ratio < 1continue;
 
                int sum_dist = 0;
                for(int j = 1; j <= go_ratio; j++) {
                    if(board[current.x + dx[i] * j][current.y + dy[i] * j] == 'E') continue;
                    else sum_dist += (board[current.x + dx[i] * j][current.y + dy[i] * j] - '0');
                }
                int nx = current.x + dx[i] * go_ratio;
                int ny = current.y + dy[i] * go_ratio;
 
                if(dist[nx][ny] > sum_dist + current.time) {
                    dist[nx][ny] = sum_dist + current.time;
                    q.offer(new Node(nx, ny, dist[nx][ny]));
                }
            }
        }
    }
 
    public static int can_go(int dir, int x, int y) {
        int ratio = 1;
        while(true) {
            int nx = x + dx[dir] * ratio;
            int ny = y + dy[dir] * ratio;
 
            if(nx < 0 || ny < 0 || nx >= h || ny >= w) break;
            if(board[nx][ny] == 'H'break;
            
            if(board[nx][ny] == 'R'return ratio - 1;
            if(board[nx][ny] == 'E' ) return ratio;
 
            ratio++;
        }
        return -1;
    }
 
    public static class Node implements Comparable<Node>{
        int x;
        int y;
        int time;
 
        public Node(int x, int y, int time) {
            this.x = x;
            this.y = y;
            this.time = time;
        }
 
        @Override
        public int compareTo(Node n) {
            return this.time - n.time;
        }
    }
}
cs