일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 메모리풀
- dfs
- 링크드리스트
- 중복 순열
- 재귀
- 그리디
- Knapsack
- BeautifulSoup
- MST
- 조합
- lis
- SSAFY
- 큐
- 문자열
- DP
- 이분 탐색
- 우선순위 큐
- 빠른 입출력
- 비트마스크
- 분할 정복
- 세그먼트 트리
- 백트래킹
- 클래스
- 순열
- 스택
- 크루스칼
- 완전 탐색
- 시뮬레이션
- 피보나치 수
- BFS
- Today
- Total
작심 24/7
[백준] 5373번 큐빙 본문
5373번: 큐빙
문제 루빅스 큐브는 삼차원 퍼즐이다. 보통 루빅스 큐브는 3×3×3개의 작은 정육면체로 이루어져 있다. 퍼즐을 풀려면 각 면에 있는 아홉 개의 작은 정육면체의 색이 동일해야 한다. 큐브는 각 면
www.acmicpc.net
내가 지금 시뮬레이션을 구현하고 있는 건지 노가다를 하고 있는 건지
잠시 현타(?) 왔던 문제이다.
그림처럼 한 면을 돌리면 그 면과 인접한 옆 면들도 돌려지기 때문에
돌리는 면과 옆 면
이 두 가지 경우로 나누어서 계산해주어야 한다.
돌리는 면에 따라 돌려져야 하는 칸들을 시계 방향으로 전개도에 표시해보았다.
1. 윗 면 (U)
2. 아랫 면 (D)
3. 앞 면 (F)
4. 뒷 면 (B)
5. 왼쪽 면 (L)
6. 오른쪽 면 (R)
기본 형태 : 1 → 2 → 3 → 4
시계 방향 : 4 → 1 → 2 → 3
반시계 방향 : 2 → 3 → 4 → 1
이런 형태가 되므로
ScanCube 함수를 통해 이 두 경우를 기본 형태로 string에 담아주고
Change 함수를 통해 시계 방향 또는 반시계 방향으로 string을 변경해준 다음
MoveCube 함수를 통해 string 값을 기본 형태로 큐브 배열에 담아준다.
돌리는 면의 옆 면은 ScanCube 함수, MoveCube 함수, string 변수 line이고
인수는 각 화살표의 시작 좌표와 끝 좌표를 넣어주었다.
돌리는 면은 ScanCube2 함수, MoveCube2 함수, string 변수 line2이고
인수는 그 면의 시작 좌표 하나만 넣어주었다.
< 예전 버전 노가다 코드>
#include <iostream>
#include <string>
using namespace std;
int T, N;
char cube[13][10];
string tmp, tmp2, line, line2, order;
void InitCube() { //큐브 초기화
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 9; j++) {
if (i < 3 && j > 2 && j < 6) cube[i][j] = 'y';
else if (i >= 3 && i < 6 && j > 2 && j < 6) cube[i][j] = 'o';
else if (i >= 6 && i < 9 && j >= 0 && j < 3) cube[i][j] = 'g';
else if (i >= 6 && i < 9 && j >= 3 && j < 6) cube[i][j] = 'w';
else if (i >= 6 && i < 9 && j < 9) cube[i][j] = 'b';
else if (i >= 9 && i < 12 && j>2 && j < 6) cube[i][j] = 'r';
else cube[i][j] = '-';
}
}
}
void ScanCube(int from_x, int from_y, int to_x, int to_y) { //옆면을 시계 방향으로 스캔
if (from_x == to_x) { //가로
if (from_y < to_y) for (int i = from_y; i <= to_y; i++) line += cube[to_x][i]; //왼쪽에서 오른쪽으로
else for (int i = from_y; i >= to_y; i--) line += cube[to_x][i]; //오른쪽에서 왼쪽으로
}
else { //세로
if (from_x < to_x) for (int i = from_x; i <= to_x; i++) line += cube[i][to_y]; //위에서 아래로
else for (int i = from_x; i >= to_x; i--) line += cube[i][to_y]; //아래에서 위로
}
}
void ScanCube2(int x, int y) { //돌리는 면을 시계 방향으로 스캔
for (int i = y; i < y + 3; i++) line2 += cube[x][i];
for (int i = x; i < x + 3; i++) line2 += cube[i][y + 2];
for (int i = y + 2; i >= y; i--) line2 += cube[x + 2][i];
for (int i = x + 2; i >= x; i--) line2 += cube[i][y];
}
void Change(char ch) { //주어진 방향에 맞게 순서 배치
if (ch == '+') {
tmp = line.substr(9, 3), tmp2 = line2.substr(9, 3);
tmp += line.substr(0, 9), tmp2 += line2.substr(0, 9);
line = tmp, line2 = tmp2;
}
else {
tmp = line.substr(3), tmp2 = line2.substr(3);
tmp += line.substr(0, 3), tmp2 += line2.substr(0, 3);
line = tmp, line2 = tmp2;
}
}
void MoveCube(int from_x, int from_y, int to_x, int to_y, int idx) { //바뀐 순서를 옆면에 시계 방향으로 집어 넣음
if (from_x == to_x) { //가로
if (from_y < to_y) for (int i = from_y; i <= to_y; i++) cube[to_x][i] = line[idx++]; //왼쪽에서 오른쪽으로
else for (int i = from_y; i >= to_y; i--) cube[to_x][i] = line[idx++]; //오른쪽에서 왼쪽으로
}
else { //세로
if (from_x < to_x) for (int i = from_x; i <= to_x; i++) cube[i][to_y] = line[idx++]; //위에서 아래로
else for (int i = from_x; i >= to_x; i--) cube[i][to_y] = line[idx++]; //아래에서 위로
}
}
void MoveCube2(int x, int y) { //바뀐 순서를 돌리는 면에 시계 방향으로 집어 넣음
int idx = 0;
for (int i = y; i < y + 3; i++) cube[x][i] = line2[idx++];
for (int i = x; i < x + 3; i++) cube[i][y + 2] = line2[idx++];;
for (int i = y + 2; i >= y; i--) cube[x + 2][i] = line2[idx++];;
for (int i = x + 2; i >= x; i--) cube[i][y] = line2[idx++];;
}
int main() {
cin >> T;
for (int t = 0; t < T; t++) {
cin >> N;
InitCube();
for (int n = 0; n < N; n++) {
cin >> order;
switch (order[0])
{
case 'U':
ScanCube(5, 3, 5, 5), ScanCube(6, 6, 8, 6), ScanCube(9, 5, 9, 3), ScanCube(8, 2, 6, 2), ScanCube2(6, 3);
Change(order[1]);
MoveCube(5, 3, 5, 5, 0), MoveCube(6, 6, 8, 6, 3), MoveCube(9, 5, 9, 3, 6), MoveCube(8, 2, 6, 2, 9), MoveCube2(6, 3);
break;
case 'D':
ScanCube(11, 3, 11, 5), ScanCube(8, 8, 6, 8), ScanCube(3, 5, 3, 3), ScanCube(6, 0, 8, 0), ScanCube2(0, 3);
Change(order[1]);
MoveCube(11, 3, 11, 5, 0), MoveCube(8, 8, 6, 8, 3), MoveCube(3, 5, 3, 3, 6), MoveCube(6, 0, 8, 0, 9), MoveCube2(0, 3);
break;
case 'F':
ScanCube(8, 3, 8, 5), ScanCube(8, 6, 8, 8), ScanCube(0, 5, 0, 3), ScanCube(8, 0, 8, 2), ScanCube2(9, 3);
Change(order[1]);
MoveCube(8, 3, 8, 5, 0), MoveCube(8, 6, 8, 8, 3), MoveCube(0, 5, 0, 3, 6), MoveCube(8, 0, 8, 2, 9), MoveCube2(9, 3);
break;
case 'B':
ScanCube(2, 3, 2, 5), ScanCube(6, 8, 6, 6), ScanCube(6, 5, 6, 3), ScanCube(6, 2, 6, 0), ScanCube2(3, 3);
Change(order[1]);
MoveCube(2, 3, 2, 5, 0), MoveCube(6, 8, 6, 6, 3), MoveCube(6, 5, 6, 3, 6), MoveCube(6, 2, 6, 0, 9), MoveCube2(3, 3);
break;
case 'L':
ScanCube(3, 3, 5, 3), ScanCube(6, 3, 8, 3), ScanCube(9, 3, 11, 3), ScanCube(0, 3, 2, 3), ScanCube2(6, 0);
Change(order[1]);
MoveCube(3, 3, 5, 3, 0), MoveCube(6, 3, 8, 3, 3), MoveCube(9, 3, 11, 3, 6), MoveCube(0, 3, 2, 3, 9), MoveCube2(6, 0);
break;
case 'R':
ScanCube(5, 5, 3, 5), ScanCube(2, 5, 0, 5), ScanCube(11, 5, 9, 5), ScanCube(8, 5, 6, 5), ScanCube2(6, 6);
Change(order[1]);
MoveCube(5, 5, 3, 5, 0), MoveCube(2, 5, 0, 5, 3), MoveCube(11, 5, 9, 5, 6), MoveCube(8, 5, 6, 5, 9), MoveCube2(6, 6);
break;
}
line = line2 = tmp = tmp2 = "";
}
for (int i = 6; i <= 8; i++) {
for (int j = 3; j <= 5; j++) cout << cube[i][j];
cout << "\n";
}
}
return 0;
}
( + 풀이 추가 2021.04.21)
1. cube배열을 6종류의 3 X 3 배열로 만들기
2. 중앙 면을 기준으로 바뀌는 옆면들을 order배열에 저장해두기
기본 로직 :
num면의, idx번째, 행or열을, 그대로or거꾸로 복사해서
num면의, idx번째, 행or열에, 그대로 집어넣는다
그냥 전개도 보면서 옆면들이 어떻게 바뀌는지 열심히 연구해서
이차원 배열에 때려 박고 함수 하나로 돌려썼다.
3. 시계 방향으로 3번 돌리면 반시계 방향이라는 사실을 이용하기
< 최신 버전 덜 노가다 코드>
#include <iostream>
using namespace std;
int T, N;
int c[300]; // 알파벳에 맞는 숫자 집어넣기용
int order[6][16] = { // num의, idx번째, 행 or 열(0 or 1)을, 그대로 or 거꾸로(0 or 1) => 이 순서대로 4번씩
{5,0,0,0,4,0,0,0,3,0,0,0,2,0,0,0},{3,2,0,0,4,2,0,0,5,2,0,0,2,2,0,0},
{0,0,1,0,3,0,1,0,1,0,1,1,5,2,1,1},{0,2,0,0,4,0,1,1,1,0,0,0,2,2,1,1},
{0,2,1,1,5,0,1,1,1,2,1,0,3,2,1,0},{0,0,0,1,2,0,1,0,1,2,0,1,4,2,1,0}
};
char cube[6][3][3]; // 3X3씩 6면 - U,D,L,F,R,B
char color[6] = { 'w', 'y', 'g', 'r', 'b', 'o' };
void rotate(int c) {
char tmp[4][3] = { 0 };
for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) tmp[i][j] = cube[c][i][j]; // 중앙 면 복사
for (int i = 0, m = 2; i < 3; i++, m--) for (int j = 0; j < 3; j++) cube[c][j][m] = tmp[i][j]; // 중앙 면에 복사한 거 넣기
for (int t = 0; t < 16; t += 4) { // 옆 면 복사
int num = order[c][t], idx = order[c][t + 1], col = order[c][t + 2], reverse = order[c][t + 3]; // num의 idx번째 행or열(col)을 그대로or거꾸로(reverse)
if (col) { // 열을 읽을 때
if (reverse) for (int i = 2; i >= 0; i--) tmp[t / 4][2 - i] = cube[num][i][idx]; // 거꾸로 읽을 때
else for (int i = 0; i < 3; i++) tmp[t / 4][i] = cube[num][i][idx]; // 그대로 읽을 때
}
else { // 행을 읽을 때
if (reverse) for (int i = 2; i >= 0; i--) tmp[t / 4][2 - i] = cube[num][idx][i]; // 거꾸로 읽을 때
else for (int i = 0; i < 3; i++) tmp[t / 4][i] = cube[num][idx][i]; // 그대로 읽을 때
}
}
int tidx = 0;
for (int t = 4; t < 20; t += 4) { // 옆 면에 복사한 거 넣기
int num = order[c][t % 16], idx = order[c][(t + 1) % 16], col = order[c][(t + 2) % 16]; // num의 idx번째 행or열(col)
if (col) { // 열에 넣을 때
for (int i = 0; i < 3; i++) cube[num][i][idx] = tmp[tidx][i];
}
else { // 행에 넣을 때
for (int i = 0; i < 3; i++) cube[num][idx][i] = tmp[tidx][i];
}
tidx++;
}
}
int main() {
c['U'] = 0, c['D'] = 1, c['L'] = 2, c['F'] = 3, c['R'] = 4, c['B'] = 5;
cin >> T;
for (int t = 1; t <= T; t++) {
for (int k = 0; k < 6; k++) for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) cube[k][i][j] = color[k]; // 큐브 초기화
cin >> N;
string input;
for (int i = 0; i < N; i++) {
cin >> input;
if (input[1] == '-') for (int j = 0; j < 3; j++) rotate(c[input[0]]); // 시계 방향 3번 == 반시계 방향
else rotate(c[input[0]]);
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) cout << cube[0][i][j];
cout << "\n";
}
}
return 0;
}
'백준' 카테고리의 다른 글
[백준] 17143번 낚시왕 (0) | 2020.07.20 |
---|---|
[백준] 16235번 나무 재테크 (0) | 2020.07.19 |
[백준] 16236번 아기 상어 (C++, JAVA) (0) | 2020.07.16 |
[백준] 12100번 2048 (Easy) (0) | 2020.07.16 |
[백준] 2096번 내려가기 (0) | 2020.07.13 |