알고리즘/백준

[JAVA/BFS,구현] 백준 13460 구슬 탈출 2

waterground 2021. 10. 22. 20:57

1. 문제

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

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

 

2. 풀이

가장 빠른 횟수를 구하기 위해 BFS를 사용한다.

  • 구슬이 굴러가면 파란 구슬과 빨간 구슬이 같이 굴러가게 되므로, 두 구슬의 위치를 모두 담은 클래스를 선언해 사용한다.
  • 맨 처음 구슬의 위치를 저장해 BFS를 시작한다.
    • 구슬들의 위치 방문여부를 확인하기 위해 4차원 배열을 사용한다.(visited[n][m][n][m])
    • 4 방향으로 빨강, 파랑 구슬을 각각 굴려가며 벽이나 구멍을 만날 때까지 이동한다
      • 구슬이 구멍을 지났을 때, 파란 구슬이면 실패한 케이스이므로 탐색을 종료한다. 빨간 구슬이면 이때까지 걸린 횟수를 계산해 출력한 후 종료한다.
      • 판(?)의 사방은 벽으로 둘러쌓여 있으므로 범위 계산을 따로 해 줄 필욘 없다.
    • 위에서 이동 할 때 구슬 겹침을 고려하지 않았으므로, 구슬이 겹칠 경우 위치를 조정한다.
  • 10번 이상 횟수가 진행될 경우 -1을 출력한다.

+) 세세한 조건 구성에서 되게 많이 틀렸다.... 다시 풀어보자....

 

3. 코드

 
import java.util.*;
import java.io.*;

class Points{
    int rX, rY, bX, bY, count;
    
    public Points(int rX, int rY, int bX, int bY, int count) {
        this.rX = rX;
        this.rY = rY;
        this.bX = bX;
        this.bY = bY;
        this.count = count;
    }
}

class Main{
    
    // 구슬탈출
    
    static int n, m;
    static char[][] map;
    static int[][] dir = {{1,0},{-1,0},{0,1},{0,-1}};
    
    public static void bfs(Points now) {
        boolean[][][][] visited = new boolean[n][m][n][m]; // 방문여부 저장
        Queue<Points> q = new LinkedList<Points>();
        q.add(now);
        
        
        while(!q.isEmpty()) {
            Points points = q.poll();
            visited[points.rX][points.rY][points.bX][points.bY] = true;
            
            if(points.count >= 10) {
                System.out.println(-1);
                return;
            }
            
            for(int i = 0; i < 4; i++) {
                            
                // 빨간 구슬 이동
                int newRX = points.rX;
                int newRY = points.rY;
                while(map[newRX + dir[i][0]][newRY + dir[i][1]] != '#'){
                    newRX += dir[i][0];
                    newRY += dir[i][1];
                    if(map[newRX][newRY] == 'O') break;
                }
                
                // 파란 구슬 이동
                int newBX = points.bX;
                int newBY = points.bY;
                while(map[newBX + dir[i][0]][newBY + dir[i][1]] != '#') {
                    newBX += dir[i][0];
                    newBY += dir[i][1];
                    if(map[newBX][newBY] == 'O') break;
                }
                
                // 파란색 구슬이 구멍에 빠지면 탐색 종료
                if(map[newBX][newBY] == 'O') 
                    continue;

                // 빨간색 구슬이 구멍에 빠지면 min 출력
                if(map[newRX][newRY] == 'O' && map[newBX][newBY] != 'O') {
                    System.out.println(points.count + 1);
                    return;
                }
                
                // 두 구슬 위치가 겹치면 위치 조정
                if(newRX == newBX && newRY == newBY) {
                    switch(i) {
                    case 0: // 남
                        if(points.rX > points.bX) newBX--;
                        else newRX--;
                        break;
                    case 1: // 북
                        if(points.rX > points.bX) newRX++;
                        else newBX++;
                        break;
                    case 2: // 동
                        if(points.rY > points.bY) newBY--;
                        else newRY--;
                        break;
                    case 3: // 서
                        if(points.rY > points.bY) newRY++;
                        else newBY++;
                        break;
                    }
                }
                
                if(!visited[newRX][newRY][newBX][newBY]) {
                    q.add(new Points(newRX, newRY, newBX, newBY, points.count + 1));
                }    
            }
        }
        System.out.println("-1");
    }
    
    public static void main (String[] args) throws java.lang.Exception{
        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 char[n][m];
        int rX = 0, rY = 0, bX = 0, bY = 0;

        for(int i = 0; i < n; i++) {
            String s = br.readLine();
            for(int j = 0; j < m; j++) {
                map[i][j] = s.charAt(j);
                if(map[i][j] == 'R') {
                    rX = i;
                    rY = j;
                } else if(map[i][j] == 'B') {
                    bX = i;
                    bY = j;
                }
            }
        }
        
        bfs(new Points(rX, rY, bX, bY, 0));
        
    }
}