알고리즘 공부/문제 풀이

[JAVA] 백준 13460 구슬 탈출 2

valid_ming 2021. 9. 17. 14:46

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

 

13460번: 구슬 탈출 2

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

www.acmicpc.net

 

 

풀이

해결 전략은 문제를 풀며 적은 내용으로 실제 작성한 코드와 상이할 수 있습니다.
변경된 부분은 왜 변경했는지 풀이 후기에 적어 놓았으니 참고 바랍니다!

 

 

코드

import java.util.*;

public class Main {

    static int N, M;
    static char[][] map;
    static int[][] d = {{-1, 1, 0, 0}, {0, 0, -1, 1}};

    public static class State{
        int Rrow, Rcol, Brow, Bcol, move;
        public State(){
            move = 0;
        }
        public State(int rr, int rc, int br, int bc, int m){
            Rrow = rr;
            Rcol = rc;
            Brow = br;
            Bcol = bc;
            move = m;
        }
    }

    public static void main(String[] args) {
        //입력
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        map = new char[N][M];

        State ini = new State();
        int[] hole = new int[2];

        for(int i=0;i<N;i++){
            String str = sc.next();
            for(int j=0;j<M;j++){
                char c = str.charAt(j);
                map[i][j] = c;
                if(c=='O'){
                    hole[0] = i;
                    hole[1] = j;
                }
                if(c=='R'){
                    ini.Rrow = i;
                    ini.Rcol = j;
                    map[i][j] = '.';
                }
                if(c=='B'){
                    ini.Brow = i;
                    ini.Bcol = j;
                    map[i][j] = '.';
                }
            }
        }


        Queue<State> q = new LinkedList<>();
        boolean[][][][] visit = new boolean[N][M][N][M];
        q.add(ini);
        visit[ini.Rrow][ini.Rcol][ini.Brow][ini.Bcol] = true;
        int answer = -1;

        while(!q.isEmpty()){
            State cur = q.poll();
            if(cur.Brow==hole[0] && cur.Bcol==hole[1]) continue;
            if(cur.Rrow==hole[0] && cur.Rcol==hole[1]){
                answer = cur.move;
                break;
            }

            for(int i=0;i<4;i++){
                if(getFirst(cur, i) <= 0) { //R우선 굴리기
                    int[] next = moveBall(cur.Rrow, cur.Rcol, cur.Brow, cur.Bcol, i);
                    int[] red = {next[0], next[1]};
                    int[] blue = {next[2], next[3]};
                    if(!visit[red[0]][red[1]][blue[0]][blue[1]] && cur.move<10){
                        visit[red[0]][red[1]][blue[0]][blue[1]] = true;
                        q.add(new State(red[0], red[1], blue[0], blue[1], cur.move+1));
                    }
                }
                else {
                    int[] next = moveBall(cur.Brow, cur.Bcol, cur.Rrow, cur.Rcol, i);
                    int[] red = {next[2], next[3]};
                    int[] blue = {next[0], next[1]};
                    if(!visit[red[0]][red[1]][blue[0]][blue[1]] && cur.move<10){
                        visit[red[0]][red[1]][blue[0]][blue[1]] = true;
                        q.add(new State(red[0], red[1], blue[0], blue[1], cur.move+1));
                    }
                }
            }
        }

        System.out.println(answer);
    }

    //음수면 R우선
    public static int getFirst(State state, int dir){
        switch(dir){
            case 0: //상
                return state.Rrow - state.Brow;
            case 1: //하
                return (state.Rrow - state.Brow)*-1;
            case 2: //좌
                return state.Rcol - state.Bcol;
            case 3: //우
                return (state.Rcol - state.Bcol)*-1;
            default: return 0;
        }
    }

    public static int[] moveBall(int r1, int c1, int r2, int c2, int dir){
        int[] next = new int[4];

        //ball1 먼저 굴리기
        int nr1 = r1 + d[0][dir];
        int nc1 = c1 + d[1][dir];

        while(0<=nr1 && nr1<N && 0<=nc1 && nc1<M){
            if(map[nr1][nc1]=='#'){
                nr1 -= d[0][dir];
                nc1 -= d[1][dir];
                break;
            }
            if(map[nr1][nc1]=='O') break;
            nr1 += d[0][dir];
            nc1 += d[1][dir];
        }

        next[0] = nr1;
        next[1] = nc1;

        //ball2 굴리기
        int nr2 = r2 + d[0][dir];
        int nc2 = c2 + d[1][dir];

        while(0<=nr2 && nr2<N && 0<=nc2 && nc2<M){
            if(map[nr2][nc2]=='O') break;
            if(map[nr2][nc2]=='#' || (nr1==nr2 && nc1==nc2)){
                nr2 -= d[0][dir];
                nc2 -= d[1][dir];
                break;
            }
            nr2 += d[0][dir];
            nc2 += d[1][dir];
        }

        next[2] = nr2;
        next[3] = nc2;

        return next;
    }
}