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 |