Hanbit the Developer

[C++] 백준 5373번: 큐빙 본문

Algorithm/백준

[C++] 백준 5373번: 큐빙

hanbikan 2021. 11. 19. 01:43

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

 

5373번: 큐빙

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

www.acmicpc.net

 

 - 관찰

단순히 rotate() 함수 하나 만들어서 cube[6][3][3]의 데이터를 적절히 변화시키기만 하면 된다. 하지만 구현이 그렇게 단순하지는 않다.

총 2개의 사항을 구현해야한다. 첫째로, 하나의 면을 돌렸을 때 영향을 받는 다른 4개의 면의 데이터 변경이며, 두번째로, 돌린 면의 3x3의 회전이다.

또한 clockwise/inverse라는 방향도 고려해야하는데, 사실 clockwise rotation을 완벽히 구현한다면 inverse로 확장하는 것은 그리 어렵지 않다.

 

 - 풀이

첫번째 구현사항인 영향받는 다른 4명의 데이터 처리이다.

 

0. UP_POS, RIGHT_POS, DOWN_POS, LEFT_POS를 위 그림과 같은 방향으로 설정한다.

1. 6면에 대해서 각 면을 회전할 때 영향을 받게 될 나머지 4면을 미리 정한다. clockwiseDimension[UP]에는 {LEFT, BACK, RIGHT, FRONT}가 있으며, 저 순서대로 덮어쓰기를 하겠다는 뜻이다. 그리고, clockwiseDimensionSequence[UP][LEFT]에는 UP을 돌리는 상황에서 LEFT가 영향받는 방향의 시퀸스를 저장한다. 다시 말해서, UP을 돌릴 때 LEFT의 상단이 움직이게 될 텐데, 이 때 (0, 0), (0, 1), (0, 2) 순서대로 값이 덮여씌워질 것이라는 뜻이다.

2. 만약 윗면을 시계방향으로 돌린다고 해보자. GREEN <- RED 방향으로, UP_POS를 따라서 복사를 하는 식으로 3번을 진행할 수가 있다. 이를 응용하여 4개의 면의 데이터를 시계방향으로 옮길 수 있다.

 

다음으로 회전하는 면의 회전 처리이다.

사실 여기는 그다지 복잡한 것이 없다. 2칸을 건너뛰어서 값을 넣어주면 된다.

 

 - 소스 코드(구현이 더러움에 주의..)

#include <iostream>
#include <map>
#define UP 0
#define LEFT 1
#define FRONT 2
#define RIGHT 3
#define BACK 4
#define DOWN 5	
#define UP_POS {{0,0},{0,1},{0,2}}
#define RIGHT_POS {{0,2},{1,2},{2,2}}
#define DOWN_POS {{2,2},{2,1},{2,0}}
#define LEFT_POS {{2,0},{1,0},{0,0}}

using namespace std;

int cube[6][3][3];

void rotate(int index, bool isClockwise) {
	int i, j, k;

	// * 영향받는 4면의 데이터 처리	 
	int offset = -1;
	int to = 1;
	if (!isClockwise) {
		offset = 1;
		to = 3;
	}

	// clockwiseDimension[UP]: UP을 돌릴 때 영향받는 면들의 순서가 L,B,R,F 이다.
	int clockwiseDimension[6][4] = {
		{LEFT,BACK,RIGHT,FRONT},{UP,FRONT,DOWN,BACK},
		{UP,RIGHT,DOWN,LEFT},{UP,BACK,DOWN,FRONT},
		{UP,LEFT,DOWN,RIGHT},{LEFT,FRONT,RIGHT,BACK}
	};

	// clockwiseDimensionSequence[UP][L]: UP을 돌릴 때 L에서 영향받는 좌표들의 순서
	pair<int, int> clockwiseDimensionSequence[6][4][3] = {
		{UP_POS,UP_POS,UP_POS,UP_POS}, // UP
		{LEFT_POS,LEFT_POS,RIGHT_POS,RIGHT_POS}, // LEFT
		{DOWN_POS,LEFT_POS,DOWN_POS,RIGHT_POS}, // FRONT
		{RIGHT_POS,LEFT_POS,LEFT_POS,RIGHT_POS}, // RIGHT			  
		{UP_POS,LEFT_POS,UP_POS,RIGHT_POS}, // BACK		  
		{DOWN_POS,DOWN_POS,DOWN_POS,DOWN_POS} // DOWN
	};

	// ABCD -> BCDA를 만드는 것을 상기하라
	// 'A'를 저장
	int tmp[3];
	for (j = 0; j < 3; j++) {
		int x = clockwiseDimensionSequence[index][0][j].first;
		int y = clockwiseDimensionSequence[index][0][j].second;
		tmp[j] = cube[clockwiseDimension[index][0]][x][y];
	}

	// BCDD
	i = 0;
	for (k=0;k<3;k++) {
		int curDimension = clockwiseDimension[index][i];
		int nextDimension = clockwiseDimension[index][(i + offset + 4)%4];

		for (j = 0; j < 3; j++) {
			pair<int, int> curPos = clockwiseDimensionSequence[index][i][j];
			pair<int, int> nextPos = clockwiseDimensionSequence[index][(i + offset + 4) % 4][j];

			cube[curDimension][curPos.first][curPos.second] = cube[nextDimension][nextPos.first][nextPos.second];
		}

		i = (i + offset + 4) % 4;
	}

	// BCDA
	for (j = 0; j < 3; j++) {
		int x = clockwiseDimensionSequence[index][to][j].first;
		int y = clockwiseDimensionSequence[index][to][j].second;
		cube[clockwiseDimension[index][to]][x][y] = tmp[j];
	}


	// * 대상 면의 회전 처리  
	i = 7;
	int saveIndex = 6;
	int loadIndex = 0;
	offset = -1;
	if (!isClockwise) {
		i = 0;
		saveIndex = 0;
		loadIndex = 6;
		offset = 1;
	}

	// rotation을 따라 2칸을 건너뛰어 복제하는 로직
	pair<int, int> rotation[] = {
		{ 0, 0 }, { 0,1 }, { 0,2 }, { 1,2 }, { 2,2 }, { 2,1 }, { 2,0 }, { 1,0 }
	};

	// 임시 저장
	tmp[0] = cube[index][rotation[saveIndex].first][rotation[saveIndex].second];
	tmp[1] = cube[index][rotation[saveIndex+1].first][rotation[saveIndex+1].second];

	// 8개 중 6개를 채워준다
	for (k = 0; k < 6; k++) {
		cube[index][rotation[i].first][rotation[i].second] = cube[index][rotation[(i + offset*2 + 8) % 8].first][rotation[(i + offset*2 + 8) % 8].second];
		i = (i + offset + 8) % 8;
	}

	// 나머지 2개를 임시 저장된 데이터를 넣어준다
	cube[index][rotation[loadIndex].first][rotation[loadIndex].second] = tmp[0];
	cube[index][rotation[loadIndex+1].first][rotation[loadIndex+1].second] = tmp[1];
}

void printDimension(int direction) {
	char colors[6] = { 'w', 'g', 'r', 'b', 'o', 'y' };
	int i, j;
	for (i = 0; i < 3; i++) {
		for (j = 0; j < 3; j++) {
			cout << colors[cube[direction][i][j]];
		}
		cout << "\n";
	}
}

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	map<char, int> dimensionForDirection = {
		{'U', 0}, {'L', 1},{'F',2},{'R',3},{'B',4},{'D',5}
	};

	int t, k;
	cin >> t;
	for (k = 0; k < t; k++) {
		int d, i, j;

		// Init a cube
		for (d = 0; d < 6; d++) {
			for (i = 0; i < 3; i++) {
				for (j = 0; j < 3; j++) cube[d][i][j] = d;
			}
		}

		// Input
		int n;
		cin >> n;

		// Solution
		for (i = 0; i < n; i++) {
			char dim, clockwise;
			cin >> dim >> clockwise;

			rotate(dimensionForDirection[dim], clockwise == '+');
		}

		printDimension(UP);
	}
}