ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 1194 달이 차오른다, 가자.
    ALGORITHM/BOJ 2021. 1. 23. 20:32

    www.acmicpc.net/problem/1194

     

    1194번: 달이 차오른다, 가자.

    첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고,

    www.acmicpc.net

    2021-01-23


    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
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.StringTokenizer;
     
    public class Main1194 {
        static class Dal {
            int x;
            int y;
            int key;
     
            public Dal(int x, int y, int key) {
                this.x = x;
                this.y = y;
                this.key = key;
            }
        }
     
        public static int N, M, answer;
        public static char arr[][];
        public static Queue<Dal> q;
        public static boolean vtd[][][], flag;
        public static int dx[] = { -1010 };
        public static int dy[] = { 0-101 };
     
        public static void solve() {
            loop:while (!q.isEmpty()) {
                int size = q.size();
                while (size > 0) {
                    Dal tmp = q.poll();
                    int x = tmp.x;
                    int y = tmp.y;
                    int key = tmp.key;
     
                    for (int i = 0; i < 4; i++) {
                        int nx = x + dx[i];
                        int ny = y + dy[i];
     
                        if (nx < 0 || ny < 0 || nx >= N || ny >= M || arr[nx][ny] == '#')
                            continue;
                        else if (!vtd[nx][ny][key]) {
                            if(arr[nx][ny] == '1') { // 탈출 하는 경우 
                                flag = true;
                                answer++;
                                break loop;
                            }
                            if (arr[nx][ny] == '.' || arr[nx][ny] == '0') { // 그냥 일반적으로 지나갈 수 있는 통로 
                                q.add(new Dal(nx, ny, key));
                                vtd[nx][ny][key] = true;
                            } else if (arr[nx][ny] >= 'A' && arr[nx][ny] <= 'F') {
                                if((key & (1 << (arr[nx][ny] - 'A'))) != 0) { //열쇠가 존재할 때
                                    q.add(new Dal(nx, ny, key));
                                    vtd[nx][ny][key] = true;
                                }
                            } else if (arr[nx][ny] >= 'a' && arr[nx][ny] <= 'f') {
                                int tmpKey = key | 1 << (arr[nx][ny] - 'a'); // 열쇠 보관
                                q.add(new Dal(nx, ny, tmpKey));
                                vtd[nx][ny][tmpKey] = true;
                            } 
                        }
                    }
                    size--;
                }
                answer++;
            }
        }
     
        public static void main(String[] args) throws Exception {
            BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st = new StringTokenizer(bf.readLine());
            N = Integer.parseInt(st.nextToken());
            M = Integer.parseInt(st.nextToken());
            arr = new char[N][M];
            q = new LinkedList<>();
            vtd = new boolean[N][M][1<<6]; // a - f : 0 - 5 
            answer = 0;
            flag = false;
            for (int i = 0; i < N; i++) {
                st = new StringTokenizer(bf.readLine());
                String str = st.nextToken();
                for (int j = 0; j < M; j++) {
                    arr[i][j] = str.charAt(j);
                    if (arr[i][j] == '0') {
                        q.add(new Dal(i, j, 0));
                    }
                }
            }
     
            solve();
            if(!flag) answer = -1;
            System.out.println(answer);
        }
    }
     
    cs

    #문제풀이 

    일반적인 bfs 탐색 문제이다. 특이한 점은 비트마스크를 이용하여야 한다.

     

    문제에 나와있는 열쇠 (a - f)문(A -F)는 각각 숫자 0 부터 5(문자 - 'a', 문자 - 'A')로 나타낼 수 있다.

     

    또한, 쉬프트 연산자를 이용해서 (1 << (문자 - 'a'))를 해주면 각 키를 이진법으로 다음과 같이 나타낼 수 있다. 문 (대문자)도 마찬가지로 계산할 수 있다.

     

    1 <<  ('a' - 'a') : 1

    1 <<  ('b' - 'a') : 10

    1 <<  ('c' - 'a') : 100

    1 <<  ('d' - 'a') : 1000

    1 <<  ('e' - 'a') : 10000

    1 <<  ('f' - 'a') : 100000

     

    이 때 비트 | (or) 연산자를 이용해서 키를 보관할 수 있다. 만약 a를 갖고 있는데 b 키를 갖을 수 있다면, 

    1 (1) | 2 (10) 을 하여 3(11)을 새로운 키로 갖고 다닐 수 있다.

     

    만약 문을 만났을 때, 갖고 있는 열쇠 중에 맞는게 있는지 찾고 싶다면, 비트 & (and)연산자를 이용해서 키를 찾을 수 있다.

    예를 들어 B 문을 만났을 때 b 키를 갖고 있는지 체크하려면, (key는 3이라고 가정)

    key (11) & (1 << ('B' - 'A')) (10) => 2 (10)로 계산 할 수 있고, 0이 아니므로 키를 갖고 있는 것을 알 수 있다.

     

    'ALGORITHM > BOJ' 카테고리의 다른 글

    [백준] 1010 다리 놓기  (0) 2021.01.27
    [백준] 1766 문제집  (0) 2021.01.27
    [백준] 1644 소수의 연속합  (0) 2021.01.20
    [백준] 2096 내려가기  (0) 2021.01.19
    [백준] 2805 나무자르기  (0) 2021.01.14

    댓글

Programming Diary