BOJ 5373
위 문제는 백준 사이트의 알고리즘 5373 문제에 관한 설명입니다.
문제
루빅스 큐브는 삼차원 퍼즐이다.
보통 루빅스 큐브는 3×3×3개의 작은 정육면체로 이루어져 있다.
퍼즐을 풀려면 각 면에 있는 아홉 개의 작은 정육면체의 색이 동일해야 한다.
큐브는 각 면을 양방향으로 90도 만큼 돌릴 수 있도록 만들어져 있다.
회전이 마친 이후에는, 다른 면을 돌릴 수 있다.
이렇게 큐브의 서로 다른 면을 돌리다 보면, 색을 섞을 수 있다.
이 문제에서는 루빅스 큐브가 모두 풀린 상태에서 시작한다.
윗 면은 흰색, 아랫 면은 노란색, 앞 면은 빨간색, 뒷 면은 오렌지색, 왼쪽 면은 초록색, 오른쪽 면은 파란색이다.
루빅스 큐브를 돌린 방법이 순서대로 주어진다.
이때, 모두 돌린 다음에 가장 윗 면의 색상을 구하는 프로그램을 작성하시오.
위의 그림은 루빅스 큐브를 푼 그림이다. 왼쪽 면은 시계방향으로 조금 돌려져 있는 상태이다.
입력
첫째 줄에 테스트 케이스의 개수가 주어진다.
테스트 케이스는 최대 100개이다.
각 테스트 케이스는 다음과 같이 구성되어져 있다.
- 첫째 줄에 큐브를 돌린 횟수 n이 주어진다. (1 ≤ n ≤ 1000)
- 둘째 줄에는 큐브를 돌린 방법이 주어진다.
각 방법은 공백으로 구분되어져 있으며, 첫 번째 문자는 돌린 면이다.
U: 윗 면, D: 아랫 면, F: 앞 면, B: 뒷 면, L: 왼쪽 면, R: 오른쪽 면이다.
두 번째 문자는 돌린 방향이다.
+인 경우에는 시계 방향 (그 면을 바라봤을 때가 기준), -인 경우에는 반시계 방향이다.
출력
각 테스트 케이스에 대해서 큐브를 모두 돌린 후의 윗 면의 색상을 출력한다.
첫 번째 줄에는 뒷 면과 접하는 칸의 색을 출력하고, 두 번째, 세 번째 줄은 순서대로 출력하면 된다.
흰색은 w, 노란색은 y, 빨간색은 r, 오렌지색은 o, 초록색은 g, 파란색은 b.
package day1229;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static char[][] up;
static char[][] down;
static char[][] front;
static char[][] back;
static char[][] left;
static char[][] right;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int testCase = Integer.parseInt(br.readLine());
for (int tc = 1; tc <= testCase; tc++) {
up = new char[3][3];
down = new char[3][3];
front = new char[3][3];
back = new char[3][3];
left = new char[3][3];
right = new char[3][3];
for(int i = 0; i < 3; i++) {
Arrays.fill(up[i], 'w');
Arrays.fill(down[i], 'y');
Arrays.fill(front[i], 'r');
Arrays.fill(back[i], 'o');
Arrays.fill(left[i], 'g');
Arrays.fill(right[i], 'b');
}
int n = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
char side;
char direction;
for (int i = 0; i < n; i++) {
String str = st.nextToken();
side = str.charAt(0);
direction = str.charAt(1);
if(direction == '+') {
switching(side);
}else {
switching(side);
switching(side);
switching(side);
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(up[i][j]);
}
System.out.println();
}
}
}
static void self(char[][] arr) {
char tmp1 = arr[0][0];
char tmp2 = arr[0][1];
char tmp3 = arr[0][2];
arr[0][0] = arr[2][0];
arr[0][1] = arr[1][0];
arr[0][2] = tmp1;
arr[2][0] = arr[2][2];
arr[1][0] = arr[2][1];
arr[2][1] = arr[1][2];
arr[2][2] = tmp3;
arr[1][2] = tmp2;
}
static void switching(char side) {
char[] temp = new char[3];
if (side == 'U') {
self(up);
for(int i = 0; i < 3; i++) {
temp[i] = back[0][i];
back[0][i] = left[0][i];
left[0][i] = front[0][i];
front[0][i] = right[0][i];
right[0][i] = temp[i];
}
} else if (side == 'D') {
self(down);
for(int i = 0; i < 3; i++) {
temp[i] = back[2][i];
back[2][i] = right[2][i];
right[2][i] = front[2][i];
front[2][i] = left[2][i];
left[2][i] = temp[i];
}
} else if (side == 'F') {
self(front);
for(int i = 0; i < 3; i++) temp[i] = up[2][i];
for(int i = 0; i < 3; i++) up[2][i] = left[2-i][2];
for(int i = 0; i < 3; i++) left[2-i][2] = down[2][i];
for(int i = 0; i < 3; i++) down[2][2-i] = right[2-i][0];
for(int i = 0; i < 3; i++) right[2-i][0] = temp[2-i];
} else if (side == 'B') {
self(back);
for(int i = 0; i < 3; i++) {
temp[i] = up[0][i];
up[0][i] = right[i][2];
right[i][2] = down[0][i];
down[0][i] = left[2-i][0];
left[2-i][0] = temp[i];
}
} else if (side == 'L') {
self(left);
for(int i = 0; i < 3; i++) {
temp[i] = up[i][0];
up[i][0] = back[2-i][2];
back[2-i][2] = down[2-i][2];
down[2-i][2] = front[i][0];
front[i][0] = temp[i];
}
} else if (side == 'R') {
self(right);
for(int i = 0; i < 3; i++) {
temp[i] = up[i][2];
up[i][2] = front[i][2];
front[i][2] = down[2-i][0];
down[2-i][0] = back[2-i][0];
back[2-i][0] = temp[i];
}
}
}
}
이번 문제는 시뮬레이션 문제 였습니다.
public class Main {
static char[][] up;
static char[][] down;
static char[][] front;
static char[][] back;
static char[][] left;
static char[][] right;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int testCase = Integer.parseInt(br.readLine());
for (int tc = 1; tc <= testCase; tc++) {
up = new char[3][3];
down = new char[3][3];
front = new char[3][3];
back = new char[3][3];
left = new char[3][3];
right = new char[3][3];
for(int i = 0; i < 3; i++) {
Arrays.fill(up[i], 'w');
Arrays.fill(down[i], 'y');
Arrays.fill(front[i], 'r');
Arrays.fill(back[i], 'o');
Arrays.fill(left[i], 'g');
Arrays.fill(right[i], 'b');
}
int n = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
char side;
char direction;
for (int i = 0; i < n; i++) {
String str = st.nextToken();
side = str.charAt(0);
direction = str.charAt(1);
if(direction == '+') {
switching(side);
}else {
switching(side);
switching(side);
switching(side);
}
}
입력부 입니다.
큐브의 각 면은 3 x 3을 기준으로 사용하기에 그 만큼의 사이즈로 만들어 줬습니다.
초기 세팅으로는 아래의 조건을 만족시켜야 합니다.
윗 면은 흰색, 아랫 면은 노란색, 앞 면은 빨간색, 뒷 면은 오렌지색, 왼쪽 면은 초록색, 오른쪽 면은 파란색이다.
따라서 각 면마다 해당 색상으로 맞춰줍니다.
그리고 들어오는 입력의 돌리는 면과, 방향을 받아줍니다.
+
의 경우 한번만 돌리면 되고,
-
의 경우 반대 방향으로 한번과 3번 돌리는 방식이 같으므로 해당 방법을 사용했습니다.
static void self(char[][] arr) {
char tmp1 = arr[0][0];
char tmp2 = arr[0][1];
char tmp3 = arr[0][2];
arr[0][0] = arr[2][0];
arr[0][1] = arr[1][0];
arr[0][2] = tmp1;
arr[2][0] = arr[2][2];
arr[1][0] = arr[2][1];
arr[2][1] = arr[1][2];
arr[2][2] = tmp3;
arr[1][2] = tmp2;
}
해당 면을 돌리는 메소드입니다.
만약 그 면을 돌린다면 그 면의 값들을 90도씩 돌려줘야합니다.
기존에 있던 모양
1 | 2 | 3 |
---|---|---|
4 | 5 | 6 |
7 | 8 | 9 |
시계방향으로 돌렸을 때
7 | 4 | 1 |
---|---|---|
8 | 5 | 2 |
9 | 6 | 3 |
반시계 방향으로 돌렸을 때
3 | 6 | 9 |
---|---|---|
2 | 5 | 8 |
1 | 4 | 7 |
위의 모습처럼 현재의 면의 값을 바꿔줬습니다.
static void switching(char side) {
char[] temp = new char[3];
if (side == 'U') {
self(up);
for(int i = 0; i < 3; i++) {
temp[i] = back[0][i];
back[0][i] = left[0][i];
left[0][i] = front[0][i];
front[0][i] = right[0][i];
right[0][i] = temp[i];
}
} else if (side == 'D') {
self(down);
for(int i = 0; i < 3; i++) {
temp[i] = back[2][i];
back[2][i] = right[2][i];
right[2][i] = front[2][i];
front[2][i] = left[2][i];
left[2][i] = temp[i];
}
} else if (side == 'F') {
self(front);
for(int i = 0; i < 3; i++) temp[i] = up[2][i];
for(int i = 0; i < 3; i++) up[2][i] = left[2-i][2];
for(int i = 0; i < 3; i++) left[2-i][2] = down[2][i];
for(int i = 0; i < 3; i++) down[2][2-i] = right[2-i][0];
for(int i = 0; i < 3; i++) right[2-i][0] = temp[2-i];
} else if (side == 'B') {
self(back);
for(int i = 0; i < 3; i++) {
temp[i] = up[0][i];
up[0][i] = right[i][2];
right[i][2] = down[0][i];
down[0][i] = left[2-i][0];
left[2-i][0] = temp[i];
}
} else if (side == 'L') {
self(left);
for(int i = 0; i < 3; i++) {
temp[i] = up[i][0];
up[i][0] = back[2-i][2];
back[2-i][2] = down[2-i][2];
down[2-i][2] = front[i][0];
front[i][0] = temp[i];
}
} else if (side == 'R') {
self(right);
for(int i = 0; i < 3; i++) {
temp[i] = up[i][2];
up[i][2] = front[i][2];
front[i][2] = down[2-i][0];
down[2-i][0] = back[2-i][0];
back[2-i][0] = temp[i];
}
}
}
실제적으로 큐브의 면적을 돌렸을 때의 동작 메소드입니다.
각 면이 어떤것인지 확인하고 큐브를 돌리는 조건식으로 들어갑니다.
아까 만들어두었던 해당 면을 돌리는 메소드를 동작시킵니다.
그리고 반복문을 통해서 주변에 있는 큐브의 값들을 하나하나 옮기면서
돌려줍니다.
else if (side == 'F') {
self(front);
for(int i = 0; i < 3; i++) temp[i] = up[2][i];
for(int i = 0; i < 3; i++) up[2][i] = left[2-i][2];
for(int i = 0; i < 3; i++) left[2-i][2] = down[2][i];
for(int i = 0; i < 3; i++) down[2][2-i] = right[2-i][0];
for(int i = 0; i < 3; i++) right[2-i][0] = temp[2-i];
}
이번 문제에서 생각지도 못했던 부분에서 오류가 발생했었습니다.
단순히 다른 방향처럼 하나씩 옮겨주는 것이 아닌
정면부분을 바꿀 때는 반복문 하나로 옮기자기엔 앞에서 바꾼 값이
이후에 영향을 주는 경우가 생겼습니다.
그래서 이 부분만 반복문을 따로따로 하나씩 만들어 줬습니다.
해당 오류를 디버깅하는 부분에서 시간을 많이 뺏겼습니다.
나머지는 그림을 하나하나 그려가면서 풀어내면 이해하기 쉬운 문제였습니다.