반응형
11-25 06:49
Today
Total
«   2024/11   »
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
관리 메뉴

개발하는 고라니

[백준] 17244번 : 아맞다우산 본문

Programming/백준

[백준] 17244번 : 아맞다우산

조용한고라니 2021. 5. 6. 15:35
반응형
 

17244번: 아맞다우산

경재씨는 저녁 약속을 가기 전 챙기지 않은 물건들이 있는 지 확인하고 있다. 필요한 물건은 전부 챙긴 것 같았고 외출 후 돌아오는 길에 경재씨는 외쳤다. "아 맞다 우산!!!" 경재 씨는 매번 외출

www.acmicpc.net


[BFS + 비트마스크]

N x M 격자 맵에서 'X'로 표시된 모든 물건을 챙기고 탈출구 'E'로 최소한의 움직임으로 나가는 방법을 찾는 문제. 격자의 크기 제한이 최대 50x50이고 물건의 개수가 최대 5개라서 비트마스킹을 안써도 메모리적인 부분에서 큰 손실은 없을 것 같으나, 물건이 모두 'X'로 동일하여 현재 내가 특정 정점에 방문했을 때, 어떤 물건을 갖고 있는 지를 체크하는 것이 비트마스킹만큼 좋은 것이 없기에 비트마스킹을 사용했다.

 

먼저 입력을 받을 때 'X'인 곳을 '0', '1', '2', ...처럼 X가 아닌 숫자로 지정해놓는다. 이는 물건에 "인덱스"를 부여하는 효과를 가져오며 물건이 몇 개 존재하는지 또한 알아낼 수 있다.

        int sY = 0, sX = 0;
        char idx = '0';

        for(int i=1; i<=n; i++) {
            char[] str = br.readLine().toCharArray();
            for (int j = 1; j <= m; j++) {
                map[i][j] = str[j - 1];

                if (map[i][j] == 'X') {
                    map[i][j] = idx++;
                    k++;
                } else if (map[i][j] == 'S') {
                    sY = i;
                    sX = j;
                }
            }
        }

그럼 이제 지도에는 S, ., #, E, 0 ~ 4가 존재할 것이고, BFS를 시작점 S에서 부터 탐색을 한다.

 

1) '0', '1', '2', '3', '4' 일 때

 

현재 방문한 정점이 위의 값 중 하나라면, 물건이 있는 곳이다. 이때 내가 이미 해당 물건을 챙겼는지 여부를 비트마스킹으로 체크한다.

만약 이미 챙겼던 물건이라면 item은 변화를 주지 않고 그저 방문한다.

 

아직 챙기지 않은 물건이라면 챙기고 방문한다.

                if(map[ny][nx] >= '0' && map[ny][nx] <= '5'){
                    int num = map[ny][nx] - '0';

                    if( (item & (1 << num)) == 0){
                        nItem = item | (1 << num);

                        visit[ny][nx][nItem] = true;
                        Q.add(new Point(ny, nx, move + 1, nItem));
                        continue;
                    }
                }

2) '#'와 숫자를 제외한 나머지

 

이때는 그냥 방문하기만 하면 된다.

 

# 종료 시퀀스

- 물건을 모두 챙겼는지? 현재 정점이 'E' 인지

# Code </>

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {

    static class Point{
        int y, x, move, item;
        public Point(int yy, int xx, int m, int it){
            y=yy;
            x=xx;
            move=m;
            item=it;
        }
    }

    //n : 높이, m : 너비, k : 물건의 개수
    static int n, m, k;
    static int[] Y = {-1,1,0,0}, X={0,0,-1,1};
    static char[][] map = new char[51][51];
    static boolean[][][] visit = new boolean[51][51][(1 << 6)];

    static int BFS(int sy, int sx) {

        Queue<Point> Q = new LinkedList<>();
        visit[sy][sx][0] = true;

        Q.add(new Point(sy, sx, 0, 0));

        while(!Q.isEmpty()){
            Point p = Q.poll();
            int y = p.y;
            int x = p.x;
            int move = p.move;
            int item = p.item;

            if(map[y][x] == 'E' && item == ((1 << k) - 1))
                return move;

            for(int a=0; a<4; a++){
                int ny = y+Y[a];
                int nx = x+X[a];
                int nItem = 0;

                if(ny < 1 || nx < 1 || ny > n || nx > m || visit[ny][nx][item] || map[ny][nx] == '#') continue;

                if(map[ny][nx] >= '0' && map[ny][nx] <= '5'){
                    int num = map[ny][nx] - '0';

                    if( (item & (1 << num)) == 0){
                        nItem = item | (1 << num);

                        visit[ny][nx][nItem] = true;
                        Q.add(new Point(ny, nx, move + 1, nItem));
                        continue;
                    }
                }

                visit[ny][nx][item] = true;
                Q.add(new Point(ny, nx, move + 1, item));
            }
        }
        return 0;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        m = Integer.parseInt(st.nextToken());
        n = Integer.parseInt(st.nextToken());

        int sY = 0, sX = 0;
        char idx = '0';

        for(int i=1; i<=n; i++) {
            char[] str = br.readLine().toCharArray();
            for (int j = 1; j <= m; j++) {
                map[i][j] = str[j - 1];

                if (map[i][j] == 'X') {
                    map[i][j] = idx++;
                    k++;
                } else if (map[i][j] == 'S') {
                    sY = i;
                    sX = j;
                }
            }
        }
        System.out.println(BFS(sY, sX));
    }
}
반응형

'Programming > 백준' 카테고리의 다른 글

[백준] 9655번 : 돌 게임  (0) 2021.05.10
[백준] 16768번 : Mooyo Mooyo  (0) 2021.05.08
[백준] 12886번 : 돌 그룹  (0) 2021.05.02
[백준] 14950번 : 정복자  (0) 2021.05.02
[백준] 2562번 : 최댓값  (0) 2021.05.01
Comments