-
반응형
https://www.acmicpc.net/problem/1473
1473번: 미로 탈출
세준이는 직사각형 모양의 미로에 갇혔다. 미로 안에는 1*1크기의 작은 방이 있다. 정사각형 모양의 각 방은 네 개의 면이 있는데, 이 네 개의 면에는 문이 있을수도 있고, 없을수도 있다. 각 방은
www.acmicpc.net
풀이
일반적인 BFS문제에서 N행M열을 돌렸는지 안돌렸는지 체크를 해주는게 문제의 포인트가 된다.
따라서 비트 마스크를 이용하여 visited[돌린 행을 체크해주는 비트][돌린 열을 체크해주는 비트][x][y] = 최소 시간 을 이용하여 문제를 해결해주었습니다.
예를 들면 4x4 행렬이 있고, (0,1) 좌표에서 방을 돌렸다고 가정을 하면
행 : 1000 => 1
열 : 0100 => 2
가 될것입니다.
이 상태에서 현재 방의 타입은 행의 0번째 비트 = 1 , 열의 1번째 비트 = 1이므로 시계방향으로 두번 돌아갔기때문에 방은 돌아가지 않은 원상태입니다.
그러면 이상태에서 다음좌표인 (0,2)의 방은 어떤상태가 될까요?
행의 0번째 비트 = 1, 열의 2번째 비트 = 0 이 되기때문에 (0,2)의 방은 시계방향으로 한번 돌아간 상태가 됩니다.
그림으로 설명하면 다음과 같습니다.
빨간 선이 돌아간 행과 열을 의미합니다. 따라서 (0,1)의 좌표는 두번 돌아갔고, (0,2)의 좌표는 한번 돌아간것을 알 수 있습니다.
이런 원리를 이용해서 O(1)의 시간으로 현재 방의 타입과 다음으로 갈 방의 타입을 알 수 있게됩니다.
현재 방의 타입과 다음방의 타입을 알면 갈 수 있는지에 대한 경우를 구할 수 있으므로, BFS를 돌려서 문제를 해결해주면 됩니다.
코드
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 int visited[][][][] = new int[1 << 7][1 << 7][7][7]; static char maze[][] = new char[7][7]; static int mv[][] = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; static boolean isIn(int n, int m, int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; } static boolean canGo(char from, char to, int direction) { if (direction == 0 || direction == 1) {//오른쪽,왼쪽 if (from == 'A' || from == 'D') { return to == 'A' || to == 'D'; } else return false; } else {//위쪽, 아래쪽 if (from == 'A' || from == 'C') { return to == 'A' || to == 'C'; } else return false; } } static char getRoomType(int row, int col, int x, int y) { boolean isTurn = ((row & (1 << x)) == 0 ^ (col & (1 << y)) == 0); if (!isTurn) return maze[x][y]; else { switch (maze[x][y]) { case 'A': case 'B': return maze[x][y]; case 'C': return 'D'; case 'D': return 'C'; default: return ' '; } } } static class Node { int row, col, x, y; public Node(int row, int col, int x, int y) { this.row = row; this.col = col; this.x = x; this.y = y; } } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); int n = Integer.valueOf(st.nextToken()); int m = Integer.valueOf(st.nextToken()); for (int i = 0; i < n; i++) { maze[i] = br.readLine().toCharArray(); } //초기화 for (int i = 0; i < 1 << 7; i++) { for (int j = 0; j < 1 << 7; j++) { for (int x = 0; x < 7; x++) { for (int y = 0; y < 7; y++) { visited[i][j][x][y] = -1; } } } } Queue<Node> q = new LinkedList<>(); q.offer(new Node(0, 0, 0, 0)); visited[0][0][0][0] = 0; int answer = Integer.MAX_VALUE; while (!q.isEmpty()) { Node node = q.poll(); int row = node.row; int col = node.col; int x = node.x; int y = node.y; char nowRoomType = getRoomType(row, col, x, y); if (x == n - 1 && y == m - 1) { answer = Math.min(answer, visited[row][col][x][y]); continue; } //안돌리고 움직일 수 있는경우 for (int d = 0; d < 4; d++) { int nx = x + mv[d][0]; int ny = y + mv[d][1]; if (!isIn(n, m, nx, ny)) continue;//범위 밖이면 건너뛰기 char nextRoomType = getRoomType(row, col, nx, ny); if (canGo(nowRoomType, nextRoomType, d) && visited[row][col][nx][ny] == -1) { visited[row][col][nx][ny] = visited[row][col][x][y] + 1; q.offer(new Node(row, col, nx, ny)); } } //해당 자리를 돌리는 경우 int turnRow = row ^ (1 << x); int turnCol = col ^ (1 << y); if (visited[turnRow][turnCol][x][y] == -1) { visited[turnRow][turnCol][x][y] = visited[row][col][x][y] + 1; q.offer(new Node(turnRow, turnCol, x, y)); } } System.out.println(answer == Integer.MAX_VALUE ? -1 : answer); } }
반응형'문제풀이 > 백준oj' 카테고리의 다른 글
[백준OJ] 21943번 연산 최대로 - Java (0) 2022.12.28 [백준OJ] 12837번 가계부 (Hard) - Java (0) 2022.12.28 [백준OJ] 8980번 택배 (Java) (0) 2022.12.27 [백준OJ] 18232번 텔레포트 경기장 (Java) (0) 2022.12.18 [백준OJ] 1793 타일링 (Java) (0) 2022.12.15 댓글