문제 접근
3x3x3 큐브를 여러 번 돌린 후 가장 윗 면의 색상을 구하는 문제이다. 각 면에 0 부터 5 까지의 번호를 부여한 후, 그에 따라 3x3 구성에서 어느 부분이 돌아가는지, 어떤 순서로 돌아가는지 저장하는 배열을 만들어 구현했다. 또한 육면체의 전개도를 기준으로 상하좌우를 고정해서 회전하면서 바뀔 때 혼동되지 않도록 했다.
문제 코드
#include <iostream>
using namespace std;
// 각 면의 현재 색을 저장하는 배열이다.
char side[6][3][3];
// 번호에 따른 색상과 위치를 나타내는 배열이다.
char color[6] = { 'r', 'w', 'b', 'o', 'y', 'g' };
char com[6] = { 'F', 'U', 'R', 'B', 'D', 'L' };
// 기준 면에 대하여 3x3 구성에서 어느 부분이 돌아가는지 저장하는 배열이다. (1~6 기준으로 저장)
// {up, right, down, left} 로 저장되며 찾을 때 10으로 나눈 나머지로 확인한다.
int part[6][4] = { {5, 6, 2, 3}, {1346, -1, -1, -1}, {-1, 125, -1, 4}, {2, 3, 5, 6}, {-1, -1, 1346, -1}, {-1, 4, -1, 125} };
// 기준 면에 대하여 어떻게 돌아가는지 저장하는 배열이다. (1~6 기준으로 저장)
// ex ) {a, b, c, d} 라면 시계 방향으로 돌릴 때 a->b->c->d 로 이동한다.
int direction[6][4] = { {2, 3, 5, 6}, {4, 3, 1, 6}, {2, 4, 5, 1}, {2, 6, 5, 3}, {1, 3, 4, 6}, {2, 1, 5, 4} };
// 회전하면서 다른 면에 역순으로 저장되는지 여부를 확인하는 배열
bool rev[6][6];
// rev 가 true 라면 1을 저장하도록 하여 역순으로 대체할 때 사용했다.
int rev_check[6];
// 각 면을 초기화하는 함수이다.
void Initialize()
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int k = 0; k < 3; ++k)
{
side[i][j][k] = color[i];
}
}
}
}
// 회전을 적용하는 함수이다.
// std : 기준면, dir : 회전 방향
void rotate_cube(int std, char dir)
{
// pos : 회전하는 부분을 확인하는 변수이다.
// cur : 이동할 값을 추출하는 면이다.
// next : 추출한 값을 저장하는 면이다.
int pos, cur, next;
// 한 번 회전할 때 각 면에서 이동하는 값들을 저장하는 배열이다.
char temp[6][3];
// 기준면이 회전한 후의 값을 저장하는 배열이다.
char temp_rot[3][3];
// 기준면 회전
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (dir == '+')
temp_rot[i][j] = side[std][2 - j][i];
else
temp_rot[2 - j][i] = side[std][i][j];
}
}
// 기준면을 회전한 값으로 대체
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
side[std][i][j] = temp_rot[i][j];
}
}
fill(&temp[0][0], &temp[5][3], '-');
fill(&rev_check[0], &rev_check[5], 0);
// 돌아가는 순서대로 처리
for (int i = 0; i < 4; ++i)
{
cur = direction[std][i] - 1;
if(dir == '+')
next = direction[std][(i + 1) % 4] - 1;
// -1 인데 음수가 될 수 있으니 +4 까지 해줘서 +3 이다.
else
next = direction[std][(i + 3) % 4] - 1;
// 3x3 구성에서 어떤 부분이 돌아가야 되는지 확인
for (int j = 0; j < 4; ++j)
{
int pos = part[std][j];
if (pos == -1)
continue;
for (int k = pos; k > 0; k /= 10)
{
// 회전하는 부분을 확인한 면이 현재 면과 같다면 회전 처리
if (k % 10 - 1 == cur)
{
// 다음 면에 역순으로 저장되는지 확인
rev_check[next] = (rev[cur][next]) ? 1 : 0;
for (int l = 0; l < 3; ++l)
{
if (j == 0)
temp[next][l] = side[cur][0][l];
else if (j == 1)
temp[next][l] = side[cur][l][2];
else if (j == 2)
temp[next][l] = side[cur][2][l];
else if (j == 3)
temp[next][l] = side[cur][l][0];
}
}
}
}
}
// 돌아가는 순서대로 처리
for (int i = 0; i < 4; ++i)
{
cur = direction[std][i] - 1;
// 3x3 구성에서 어떤 부분이 돌아가야 되는지 확인
for (int j = 0; j < 4; ++j)
{
int pos = part[std][j];
if (pos == -1)
continue;
for (int k = pos; k > 0; k /= 10)
{
// 회전하는 부분을 확인한 면이 현재 면과 같다면 회전 처리
if (k % 10 - 1 == cur)
{
for (int l = 0; l < 3; ++l)
{
// 역순이라면 (2-2*l) 을 더해 2-l 로 처리
if (j == 0)
side[cur][0][l] = temp[cur][l + (2 - 2 * l) * rev_check[cur]];
else if (j == 1)
side[cur][l][2] = temp[cur][l + (2 - 2 * l) * rev_check[cur]];
else if (j == 2)
side[cur][2][l] = temp[cur][l + (2 - 2 * l) * rev_check[cur]];
else if (j == 3)
side[cur][l][0] = temp[cur][l + (2 - 2 * l) * rev_check[cur]];
}
}
}
}
}
}
int main(void)
{
int T, n;
// command[2] 로 하면 런타임 에러난다.
// 버퍼에 있는 띄어쓰기까지 읽어와서 null 값이 들어갈 공간이 없어서 생기는 문제인 것 같다.
char command[3];
fill(&rev[0][0], &rev[5][6], false);
// 회전할 때 역순으로 저장해야하는 면들 확인
rev[1][5] = rev[1][3] = rev[2][4] = rev[3][1] = rev[3][4] = rev[4][2] = rev[4][3] = rev[5][1] = true;
cin >> T;
while (T--)
{
Initialize();
cin >> n;
while (n--)
{
cin >> command;
for (int i = 0; i < 6; ++i)
if (com[i] == command[0])
rotate_cube(i, command[1]);
}
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
cout << side[1][i][j];
}
cout << '\n';
}
}
}
느낀 점
이 문제도 군대에 있던 친구들과 풀기로 한 문제였다. 처음 봤을 때는 이게 왜 플레인지 이해가 안 됐는데, 풀다보니 이해됐다 ㅋㅋㅋ 내가 구현 문제에 약하다는 것도 다시 한 번 깨달았다. 그래도 이번에 큐빙 문제를 풀면서 큰 문제를 어떻게 작은 문제로 나누고, 이 문제들을 해결하기 위해 어떤 기능이 필요한 지 찾는 과정을 통해 PS 접근 방법에 대해 약간이나마 감을 잡은 것 같다. 구현 문제에 대한 한 줌의 자신감도 얻을 수 있었다!
'개발 > 알고리즘' 카테고리의 다른 글
백준 1467번 : 수 지우기 (0) | 2022.07.02 |
---|---|
백준 5719번 : 거의 최단 경로 (0) | 2022.07.02 |
21년 8월 알고리즘 스터디 5주차 (0) | 2022.07.02 |
21년 8월 알고리즘 스터디 4주차 (0) | 2022.07.02 |
21년 8월 알고리즘 스터디 3주차 (0) | 2022.07.02 |