BOJ 5373

2020-12-29

위 문제는 백준 사이트의 알고리즘 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];
		}

이번 문제에서 생각지도 못했던 부분에서 오류가 발생했었습니다.

단순히 다른 방향처럼 하나씩 옮겨주는 것이 아닌

정면부분을 바꿀 때는 반복문 하나로 옮기자기엔 앞에서 바꾼 값이

이후에 영향을 주는 경우가 생겼습니다.

그래서 이 부분만 반복문을 따로따로 하나씩 만들어 줬습니다.

해당 오류를 디버깅하는 부분에서 시간을 많이 뺏겼습니다.

나머지는 그림을 하나하나 그려가면서 풀어내면 이해하기 쉬운 문제였습니다.

큐빙