본문 바로가기
Algorithm/Java

[BOJ] 5373 : 큐빙 [P5]

by 코코형아 2024. 3. 10.

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

 

5373번: 큐빙

각 테스트 케이스에 대해서 큐브를 모두 돌린 후의 윗 면의 색상을 출력한다. 첫 번째 줄에는 뒷 면과 접하는 칸의 색을 출력하고, 두 번째, 세 번째 줄은 순서대로 출력하면 된다. 흰색은 w, 노란

www.acmicpc.net

 

 

 

 

 

[문제]

루빅스 큐브는 삼차원 퍼즐이다. 보통 루빅스 큐브는 3×3×3개의 작은 정육면체로 이루어져 있다. 퍼즐을 풀려면 각 면에 있는 아홉 개의 작은 정육면체의 색이 동일해야 한다.

큐브는 각 면을 양방향으로 90도 만큼 돌릴 수 있도록 만들어져 있다. 회전이 마친 이후에는, 다른 면을 돌릴 수 있다. 이렇게 큐브의 서로 다른 면을 돌리다 보면, 색을 섞을 수 있다.

이 문제에서는 루빅스 큐브가 모두 풀린 상태에서 시작한다. 윗 면은 흰색, 아랫 면은 노란색, 앞 면은 빨간색, 뒷 면은 오렌지색, 왼쪽 면은 초록색, 오른쪽 면은 파란색이다.

루빅스 큐브를 돌린 방법이 순서대로 주어진다. 이때, 모두 돌린 다음에 가장 윗 면의 색상을 구하는 프로그램을 작성하시오.

위의 그림은 루빅스 큐브를 푼 그림이다. 왼쪽 면은 시계방향으로 조금 돌려져 있는 상태이다.

 

[입력]

첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스는 최대 100개이다. 각 테스트 케이스는 다음과 같이 구성되어져 있다.

  • 첫째 줄에 큐브를 돌린 횟수 n이 주어진다. (1 ≤ n ≤ 1000)
  • 둘째 줄에는 큐브를 돌린 방법이 주어진다. 각 방법은 공백으로 구분되어져 있으며, 첫 번째 문자는 돌린 면이다. U: 윗 면, D: 아랫 면, F: 앞 면, B: 뒷 면, L: 왼쪽 면, R: 오른쪽 면이다. 두 번째 문자는 돌린 방향이다. +인 경우에는 시계 방향 (그 면을 바라봤을 때가 기준), -인 경우에는 반시계 방향이다.

 

[출력]

각 테스트 케이스에 대해서 큐브를 모두 돌린 후의 윗 면의 색상을 출력한다. 첫 번째 줄에는 뒷 면과 접하는 칸의 색을 출력하고, 두 번째, 세 번째 줄은 순서대로 출력하면 된다. 흰색은 w, 노란색은 y, 빨간색은 r, 오렌지색은 o, 초록색은 g, 파란색은 b.

 

[예제 입력 1]

4
1
L-
2
F+ B+
4
U- D- L+ R+
10
L- U- L+ U- L- U- U- L+ U+ U+

[예제 출력 1]

rww
rww
rww
bbb
www
ggg
gwg
owr
bwb
gwo
www
rww

 

 

[내 풀이]

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/*
	문제 : [P5] 큐빙 - 5373번
	결과 : 통과
	성능 요약 : 메모리 35500KB, 시간 320ms
	아이디어 : 구현과 시뮬레이션으로 풀었습니다.
	    1. 3차원 배열에 각 큐브의 색상 정보를 넣어주었습니다.
	    2. 요구사항에 맞춰 큐브를 돌려가며 3차원 배열을 업데이트 해주었습니다.
	    3. 각 연산마다 해당 면을 90도 돌려야 하는데 돌리는 방향을 면마다 고정 시켜주었습니다.
	    4. 반시계로 돌리는 - 연산은 시계방향으로 큐브를 회전시키는 + 연산을 3번 해주었습니다.
*/

public class Main {
    // 위 - 0(w), 아래 - 1(y), 앞 - 2(r), 뒷 - 3(o), 왼 - 4(g), 오 - 5(b)
    // U : 윗면, D : 아랫면, F : 앞면, B : 뒷면, L : 왼쪽면, R : 오른쪽면
    static String[] oper;
    // 6개의 면, 면 마다 3*3 배열
    static char[][][] cube = new char[6][3][3];

    // 각 면을 90도 돌리는 연산
    static void rotate(int index) {
        char[][] arrTemp = new char[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                arrTemp[i][j] = cube[index][i][j];
            }
        }

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                cube[index][i][j] = arrTemp[3-1-j][i];
            }
        }
    }
    static void R() { // R 연산
        char[] temp = new char[3];
        temp[0] = cube[0][0][2];
        temp[1] = cube[0][1][2];
        temp[2] = cube[0][2][2];

        // 2(0 2, 1 2, 2 2) -> 0(0 2, 1 2, 2 2)
        for (int i = 0; i < 3; i++) cube[0][i][2] = cube[2][i][2];

        // 1(0 2, 1 2, 2 2) -> 2(0 2, 1 2, 2 2)
        for (int i = 0; i < 3; i++) cube[2][i][2] = cube[1][i][2];

        // 3(2 0, 1 0, 0 0) -> 1(0 2, 1 2, 2 2)
        for (int i = 0; i < 3; i++) cube[1][i][2] = cube[3][2-i][0];

        // 0(0 2, 1 2, 2 2) -> 3(2 0, 1 0, 0 0)
        for (int i = 0; i < 3; i++) cube[3][2-i][0] = temp[i];

        rotate(5);
    }
    static void L() { // L 연산
        char[] temp = new char[3];
        temp[0] = cube[0][0][0];
        temp[1] = cube[0][1][0];
        temp[2] = cube[0][2][0];

        // 3(2 2, 1 2, 0 2) -> 0(0 0, 1 0, 2 0)
        for (int i = 0; i < 3; i++) cube[0][i][0] = cube[3][2-i][2];

        // 1(0 0, 1 0, 2 0) -> 3(2 2, 1 2, 0 2)
        for (int i = 0; i < 3; i++) cube[3][2-i][2] = cube[1][i][0];

        // 2(0 0, 1 0, 2 0) -> 1(0 0, 1 0, 2 0)
        for (int i = 0; i < 3; i++) cube[1][i][0] = cube[2][i][0];

        // 0(0 0, 1 0, 2 0) -> 2(0 0, 1 0, 2 0)
        for (int i = 0; i < 3; i++) cube[2][i][0] = temp[i];

        rotate(4);
    }
    static void B() { // B 연산
        char[] temp = new char[3];
        temp[0] = cube[0][0][0];
        temp[1] = cube[0][0][1];
        temp[2] = cube[0][0][2];

        // 5(0 2, 1 2, 2 2) -> 0(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[0][0][i] = cube[5][i][2];

        // 1(2 0, 2 1, 2 2) -> 5(2 2, 1 2, 0 2)
        for (int i = 0; i < 3; i++) cube[5][2-i][2] = cube[1][2][i];

        // 4(0 0, 1 0, 2 0) -> 1(2 0, 2 1, 2 2)
        for (int i = 0; i < 3; i++) cube[1][2][i] = cube[4][i][0];

        // 0(0 2, 0 1, 0 0) -> 4(0 0, 1 0, 2 0)
        for (int i = 0; i < 3; i++) cube[4][i][0] = temp[2-i];

        rotate(3);
    }
    static void F() { // F 연산
        char[] temp = new char[3];
        temp[0] = cube[0][2][0];
        temp[1] = cube[0][2][1];
        temp[2] = cube[0][2][2];

        // 4(2 2, 1 2, 0 2) -> 0(2 0, 2 1, 2 2)
        for (int i = 0; i < 3; i++) cube[0][2][i] = cube[4][2-i][2];

        // 1(0 0, 0 1, 0 2) -> 4(0 2, 1 2, 2 2)
        for (int i = 0; i < 3; i++) cube[4][i][2] = cube[1][0][i];

        // 5(2 0, 1 0, 0 0) -> 1(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[1][0][i] = cube[5][2-i][0];

        // 0(2 0, 2 1, 2 2) -> 5(0 0, 1 0, 2 0)
        for (int i = 0; i < 3; i++) cube[5][i][0] = temp[i];

        rotate(2);
    }
    static void D() { // D 연산
        char[] temp = new char[3];
        temp[0] = cube[2][2][0];
        temp[1] = cube[2][2][1];
        temp[2] = cube[2][2][2];

        // 4 -> 2
        for (int i = 0; i < 3; i++) cube[2][2][i] = cube[4][2][i];

        // 3 -> 4
        for (int i = 0; i < 3; i++) cube[4][2][i] = cube[3][2][i];

        // 5 -> 3
        for (int i = 0; i < 3; i++) cube[3][2][i] = cube[5][2][i];

        // 2 -> 5
        for (int i = 0; i < 3; i++) cube[5][2][i] = temp[i];

        rotate(1);
    }
    static void U() { // U 연산
        char[] temp = new char[3];
        temp[0] = cube[5][0][0];
        temp[1] = cube[5][0][1];
        temp[2] = cube[5][0][2];

        // 3(0 0, 0 1, 0 2) -> 5(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[5][0][i] = cube[3][0][i];

        // 4(0 0, 0 1, 0 2) -> 3(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[3][0][i] = cube[4][0][i];

        // 2(0 0, 0 1, 0 2) -> 4(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[4][0][i] = cube[2][0][i];

        // 5 -> 2(0 0, 0 1, 0 2)
        for (int i = 0; i < 3; i++) cube[2][0][i] = temp[i];

        // 배열 90도 돌리기
        // [i, j] <- [j, N-1-i]
        // [N-1-j, i] <- [i, j]
        rotate(0);
    }

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());

        for (int tc = 0; tc < T; tc++) {
            makeCube();

            int N = Integer.parseInt(br.readLine());
            oper = new String[N];
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int i = 0; i < N; i++) {
                // 각 연산을 토큰으로 분리하여 입력 받음
                oper[i] = st.nextToken();
            }

            for (int i = 0; i < oper.length; i++) {
                char direction = oper[i].charAt(0);
                char plusMinus = oper[i].charAt(1);

                if (direction == 'U') {
                    if (plusMinus == '+') U();
                    else {U(); U(); U();} // - 연산은 + 연산을 3번 해줌

                } else if (direction == 'D') {
                    if (plusMinus == '+') D();
                    else {D(); D(); D();}

                } else if (direction == 'F') {
                    if (plusMinus == '+') F();
                    else {F(); F(); F();}

                } else if (direction == 'B') {
                    if (plusMinus == '+') B();
                    else {B(); B(); B();}

                } else if (direction == 'L') {
                    if (plusMinus == '+') L();
                    else {L(); L(); L();}

                } else if (direction == 'R') {
                    if (plusMinus == '+') R();
                    else {R(); R(); R();}
                }
            }
            printCube();
        }
    }

    static void makeCube() {
        // 큐브 초기값 설정
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                cube[0][i][j] = 'w';
                cube[1][i][j] = 'y';
                cube[2][i][j] = 'r';
                cube[3][i][j] = 'o';
                cube[4][i][j] = 'g';
                cube[5][i][j] = 'b';
            }
        }
    }

    // 큐브를 출력해주는 함수
    static void printCube() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.print(cube[0][i][j]);
            }
            System.out.println();
        }
    }
}

 

 

<회고>

복잡한 알고리즘은 없고, 정말 단순히 빡구현 + 빡시뮬레이션 돌려야하는 문제였습니다.

구현을 하면서 정말 헷갈리는 부분이 많은데, 몇가지 팁을 이야기해보자면

 

1. 각 면을 내가 바라보았을때, 왼쪽 상단 부분을 2차원배열의 (0, 0)으로 설정한다.

=> 이렇게 하면 큐브를 회전하였을 때 항상 회전한 면을 90도 회전해줘야 하는데, 그 부분이 각 면마다 동일하게 적용된다.

 

2. 반시계방향 회전 = 시계방향 회전*3

=> 조금만 생각해보면 알 수 있는 내용인데, 단순 구현이구나!! 하면서 달려들면 자칫 놓칠수도 있음..

 

3. 이러한 복잡한 구현은 각 함수를 간단명료하게 써주기+(주석)

=> 그래야 이런 복잡한 구현 문제에서 실수를 했을 때, 내가 어디서 실수 했구나 확인하기가 쉽다.

=> 코드 항상 깔끔하게 작성해보기!

'Algorithm > Java' 카테고리의 다른 글

[BOJ] 12865 : 평범한 배낭 [G5]  (1) 2024.03.29
[BOJ] 13913 : 숨바꼭질 [G4]  (0) 2024.03.18
[BOJ] 7576 : 토마토 [G5]  (0) 2024.03.09
[BOJ] 10972 : 다음 순열 [S3]  (1) 2024.02.13
[BOJ] 4179 : 불! [G4]  (0) 2024.02.12