알고리즘/백준

백준 15653 구슬 탈출 4(JAVA)

우리로 2020. 10. 17. 22:14

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

 

15653번: 구슬 탈출 4

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

www.acmicpc.net

 

면접 준비때문에 너무 바쁜걸...

 

간만에 한 문제 풀었다 ㅠㅠ

 

이 문제는 주어진 조건대로 풀면된다! 간단함!

 

import java.io.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.StringTokenizer;

public class boj15653 {

    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class Marble {
        private int r, c;
        public boolean inHole;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Marble marble = (Marble) o;
            return r == marble.r &&
                    c == marble.c;
        }

        @Override
        public int hashCode() {
            return Objects.hash(r, c);
        }

        @Override
        public String toString() {
            return "r = " + this.r + " c = " + this.c;
        }

        Marble(int a, int b) {
            r = a;
            c = b;
            this.inHole = false;
        }

        Marble(Marble a) {
            r = a.r;
            c = a.c;
            inHole = false;
        }

        public void tileLeft() {
            this.c--;
        }

        public void tileRight() {
            this.c++;
        }

        public void tileUp() {
            this.r--;
        }

        public void tileDown() {
            this.r++;
        }
    }

    static class Board {
        private int R, C;
        private int hole_r, hole_c;
        private Character[][] map;
        private Marble red, blue;

        private int[][][][] visited = new int[11][11][11][11];

        Board(int a, int b) {
            R = a;
            C = b;

            map = new Character[a][b];

            for (int i = 0; i < 11; i++) {
                for (int j = 0; j < 11; j++) {
                    for (int k = 0; k < 11; k++) {
                        for (int l = 0; l < 11; l++) {
                            visited[i][j][k][l] = Integer.MAX_VALUE;
                        }
                    }
                }
            }
        }

        public void setBoard() throws IOException {
            for (int i = 0; i < R; i++) {
                StringTokenizer st = new StringTokenizer(br.readLine());
                String s = st.nextToken();
                for (int j = 0; j < C; j++) {

                    map[i][j] = s.charAt(j);
                    if (map[i][j] == 'R') {
                        red = new Marble(i, j);
                    } else if (map[i][j] == 'B') {
                        blue = new Marble(i, j);
                    } else if (map[i][j] == 'O') {
                        hole_c = j;
                        hole_r = i;
                    }
                }
            }
        }

        public boolean noMove(Marble aM, Marble bM, Marble taM, Marble tbM){
            return aM.equals(taM) && bM.equals(tbM);
        }

        public boolean nextMove(Marble newm, Marble newb, Marble m, Marble b, int count){
            return !noMove(newm, newb, m, b) && (visited[newm.r][newm.c][newb.r][newb.c] > count);
        }

        public int relatedWithHole(Marble m ,Marble b){
            if (isHole(b)) {
                // blue to hole
                return -1 ;
            } else if (isHole(m)) {
                // red to hole but blue not in hole
                return 0;
            } else {
                return 1;
            }
        }

        public int tilting(Marble m, Marble b, int count) {

            int newCount = Integer.MAX_VALUE;
            // Up
            Marble newm = new Marble(m);
            Marble newb = new Marble(b);

            if (newm.r < newb.r) {
                tiltUp(newm, newb);
            } else {
                tiltUp(newb, newm);
            }

            if(newm.inHole && !newb.inHole) {
                return count;
            }

            if (!newb.inHole && nextMove(newm, newb, m, b, count)) {

                visited[newm.r][newm.c][newb.r][newb.c] = count;
                int result = tilting(newm, newb, count + 1);
                if (result != -1)
                    newCount = Math.min(newCount, result);
            }

            // Down
            newm = new Marble(m);
            newb = new Marble(b);

            if (newm.r > newb.r) {
                tiltDown(newm, newb);
            } else {
                tiltDown(newb, newm);
            }
            if(newm.inHole && !newb.inHole) {
                return count;
            }
            if (!newb.inHole && nextMove(newm, newb, m, b, count)) {

                visited[newm.r][newm.c][newb.r][newb.c] = count;
                int result = tilting(newm, newb, count + 1);
                if (result != -1)
                    newCount = Math.min(newCount, result);
            }
            // Left
            newm = new Marble(m);
            newb = new Marble(b);

            if (newm.c > newb.c) {
                tiltLeft(newb, newm);
            } else {
                tiltLeft(newm, newb);
            }
            if(newm.inHole && !newb.inHole) {
                return count;
            }
            if (!newb.inHole && nextMove(newm, newb, m, b, count)) {

                visited[newm.r][newm.c][newb.r][newb.c] = count;
                int result = tilting(newm, newb, count + 1);
                if (result != -1)
                    newCount = Math.min(newCount, result);
            }
            // Right
            newm = new Marble(m);
            newb = new Marble(b);

            if (newm.c > newb.c) {
                tiltRight(newm, newb);
            } else {
                tiltRight(newb, newm);
            }
            if(newm.inHole && !newb.inHole) {
                return count;
            }
            if (!newb.inHole && nextMove(newm, newb, m, b, count)) {

                visited[newm.r][newm.c][newb.r][newb.c] = count;
                int result = tilting(newm, newb, count + 1);
                if (result != -1)
                    newCount = Math.min(newCount, result);
            }

            return newCount;
        }

        public boolean isRange(Marble m) {
            return m.r >= 0 && m.r < R && m.c >= 0 && m.c < C && (map[m.r][m.c] != '#');
        }

        public boolean isHole(Marble m) {
            return m.r == hole_r && m.c == hole_c;
        }

        public boolean isCrash(Marble m, Marble b) {
            return ((m.r == b.r) && (m.c == b.c));
        }

        // m이 더 왼쪽에 있다.
        public void tiltLeft(Marble m, Marble b) {
            while (true) {
                m.tileLeft();
                if (!isRange(m)) {
                    m.tileRight();
                    break;
                }

                if (isHole(m)) {
                    m.r = m.c = -1;
                    m.inHole = true;
                    break;
                }
            }

            while (true) {
                b.tileLeft();
                if (!isRange(b) || isCrash(b, m)) {
                    b.tileRight();
                    break;
                }

                if (isHole(b)) {
                    b.r = b.c = -1;
                    b.inHole = true;
                    break;
                }
            }
        }

        public void tiltRight(Marble m, Marble b) {
            while (true) {
                m.tileRight();
                if (!isRange(m)) {
                    m.tileLeft();
                    break;
                }

                if (isHole(m)) {
                    m.r = m.c = -1;
                    m.inHole = true;
                    break;
                }
            }

            while (true) {
                b.tileRight();
                if (!isRange(b) || isCrash(b, m)) {
                    b.tileLeft();
                    break;
                }

                if (isHole(b)) {
                    b.r = b.c = -1;
                    b.inHole = true;
                    break;
                }
            }
        }

        public void tiltUp(Marble m, Marble b) {
            while (true) {
                m.tileUp();
                if (!isRange(m)) {
                    m.tileDown();
                    break;
                }

                if (isHole(m)) {
                    m.r = m.c = -1;
                    m.inHole = true;
                    break;
                }
            }

            while (true) {
                b.tileUp();
                if (!isRange(b) || isCrash(b, m)) {
                    b.tileDown();
                    break;
                }

                if (isHole(b)) {
                    b.r = b.c = -1;
                    b.inHole = true;
                    break;
                }
            }
        }

        public void tiltDown(Marble m, Marble b) {
            while (true) {
                m.tileDown();
                if (!isRange(m)) {
                    m.tileUp();
                    break;
                }

                if (isHole(m)) {
                    m.r = m.c = -1;
                    m.inHole = true;
                    break;
                }
            }

            while (true) {
                b.tileDown();
                if (!isRange(b) || isCrash(b, m)) {
                    b.tileUp();
                    break;
                }

                if (isHole(b)) {
                    b.r = b.c = -1;
                    b.inHole = true;
                    break;
                }
            }
        }
    }

    static int R, C;

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

        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());

        Board board = new Board(R, C);

        // Input Setting
        board.setBoard();

        // Solve Problem
        int res = board.tilting(board.red, board.blue, 1);

        bw.write((res == Integer.MAX_VALUE ? -1 : res)                 + "\n");
        bw.flush();
    }
}