Algorithms/백준(BOJ)

[백준 5373] 큐빙(C++)

coco_daddy 2024. 9. 30. 02:09

큐빙

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

문제

문제 접근

  • 문제 자체의 이해가 그다지 어렵지는 않았다.
    • 큐브의 각 면이 w(white), y(yellow), r(red), o(orange), g(green), b(blue)로 주어져있다.
    • 각 테스트 케이스 별로 면을 돌린 뒤에 top의 큐브가 어떤 패턴인지 출력하는 문제이다.
  • 큐브의 각 면을 저장할 배열과 적절하게 시계방향 또는 반시계 방향으로 돌리는 함수만 만들면 된다. 너무 간단하다!라고 생각했다.

풀이 힌트

큐브의 각 면 저장

착시현상에 속지 말자

각 면은 2차원 배열 char side[3][4]로 표현할 수 있다. 문자열(char 배열)이기 때문에 null 자리 포함

각 면을 회전시키는 함수

  • 각 면의 돌리는 방향은 + 또는 -으로 주어진다.

시계방향의 경우 기존 i는 j로, j는 N - 1 - i와 대응된다.

반시계방향의 경우 기존 i는 N - 1 - j로, j는 i와 대응된다.

여기서 N - 1은 마지막 요소를 가리킨다.

  • 하나의 면은 인접한 4개의 면과 상호작용해야 하기 때문에 어떤 면과 연결할지를 결정해야 한다.

자신이 이해하기 편한 방식으로 잘 결정하는 것이 좋을 것 같다. 가장 끔찍한 노가다를 경험했다.

구현에서 가장 실수가 잦을 것이라 생각하는 부분이다.

  • 어느 부분과 상호작용할지 결정했다면, 회전 함수를 구현하자.

UP을 예시로 보자.

각 면의 인접한 면을 보면 해당 면이 회전하는 방향대로 회전할 수 있음을 발견할 수 있다.

회전하는 함수를 하나만 구현하면 5 * 5 배열을 회전시키면 되기 때문에 문제가 더 간단해진다!

한 면과 상하좌우로 인접한 가리킬 char 포인터 배열을 다음과 같이 초기화한다. (UP을 예시로 본다.)

인덱스가 우하향으로 진행하기 때문에 BACK과 RIGHT는 반대로 진행한다는 점에 주의하자.

for (int i = 0; i < 3; ++i) {
    // adj up
    cube_side[UP][0][i + 1] = &(cube[BACK][0][2 - i]);
    // adj down
    cube_side[UP][4][i + 1] = &(cube[FRONT][0][i]);
    // adj left
    cube_side[UP][i + 1][0] = &(cube[LEFT][0][i]);
    // adj right
    cube_side[UP][i + 1][4] = &(cube[RIGHT][0][2 - i]);
}

 

초기화를 이 악물고 눈 부릅뜨고 꼼꼼히 해준다면, 문제 해결은 어렵지 않다.

초기화가 가장 어려운 문제였다.

코드

주의점

  • 각 테스트 케이스는 모든 면이 처음 상태로 돌아간 뒤 다시 계산해야 한다.
#include <iostream>

using namespace std;

enum e_cube {
    UP,
    DOWN,
    FRONT,
    BACK,
    LEFT,
    RIGHT
};

int N, C;
char input[3];
char cube[7][4][4];
char *cube_side[6][6][6];


void rotate(int side, bool is_plus) {
    char temp[6][6];

    for (int i = 0; i < 6; ++i) {
        for (int j = 0; j < 6; ++j) {
            if (cube_side[side][i][j] != 0)
                temp[i][j] = *(cube_side[side][i][j]);
        }
    }
    if (!is_plus) {
        for (int i = 0; i < 6; ++i) {
            for (int j = 0; j < 6; ++j) {
                if (cube_side[side][i][j] != 0)
                    *(cube_side[side][i][j]) = temp[j][4- i];
            }
        }
    } else {
        for (int i = 0; i < 6; ++i) {
            for (int j = 0; j < 6; ++j) {
                if (cube_side[side][i][j] != 0)
                    *(cube_side[side][i][j]) = temp[4- j][i];
            }
        }
    }
}

void spin_cube(char side, bool is_plus) {
    // dir에 따라 90도 혹은 -90도 회전
    // 영향을 받는 인접한 4면 변경
    if (side == 'U') {
        rotate(UP, is_plus);
    } else if (side == 'D') {
        rotate(DOWN, is_plus);
    } else if (side == 'F') {
        rotate(FRONT, is_plus);
    } else if (side == 'B') {
        rotate(BACK,is_plus);
    } else if (side == 'L') {
        rotate(LEFT, is_plus);
    } else {
        rotate(RIGHT, is_plus);
    }
}

void init_pointer() {
    // up
    for (int i = 0; i < 3; ++i) {
        // adj up
        cube_side[UP][0][i + 1] = &(cube[BACK][0][2 - i]);
        // adj down
        cube_side[UP][4][i + 1] = &(cube[FRONT][0][i]);
        // adj left
        cube_side[UP][i + 1][0] = &(cube[LEFT][0][i]);
        // adj right
        cube_side[UP][i + 1][4] = &(cube[RIGHT][0][2 - i]);
    }
    // down
    for (int i = 0; i < 3; ++i) {
        cube_side[DOWN][0][i + 1] = &(cube[FRONT][2][i]);
        cube_side[DOWN][4][i + 1] = &(cube[BACK][2][2 - i]);
        cube_side[DOWN][i + 1][0] = &(cube[LEFT][2][2 - i]);
        cube_side[DOWN][i + 1][4] = &(cube[RIGHT][2][i]);
    }
    // front
    for (int i = 0; i < 3; ++i) {
        cube_side[FRONT][0][i + 1] = &(cube[UP][2][i]);
        cube_side[FRONT][4][i + 1] = &(cube[DOWN][0][i]);
        cube_side[FRONT][i + 1][0] = &(cube[LEFT][i][2]);
        cube_side[FRONT][i + 1][4] = &(cube[RIGHT][i][0]);
    }
    // back
    for (int i = 0; i < 3; ++i) {
        cube_side[BACK][0][i + 1] = &(cube[UP][0][2 - i]);
        cube_side[BACK][4][i + 1] = &(cube[DOWN][2][2 - i]);
        cube_side[BACK][i + 1][0] = &(cube[RIGHT][i][2]);
        cube_side[BACK][i + 1][4] = &(cube[LEFT][i][0]);
    }
    // left
    for (int i = 0; i < 3; ++i) {
        cube_side[LEFT][0][i + 1] = &(cube[UP][i][0]);
        cube_side[LEFT][4][i + 1] = &(cube[DOWN][2 - i][0]);
        cube_side[LEFT][i + 1][0] = &(cube[BACK][i][2]);
        cube_side[LEFT][i + 1][4] = &(cube[FRONT][i][0]);
    }
    // right
    for (int i = 0; i < 3; ++i) {
        cube_side[RIGHT][0][i + 1] = &(cube[UP][2 - i][2]);
        cube_side[RIGHT][4][i + 1] = &(cube[DOWN][i][2]);
        cube_side[RIGHT][i + 1][0] = &(cube[FRONT][i][2]);
        cube_side[RIGHT][i + 1][4] = &(cube[BACK][i][0]);
    }
}

void init() {
    string side_color = "wyrogb";
    for (int i = 0; i < 6; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 3; ++k) {
                cube[i][j][k] = side_color[i];
                cube_side[i][j + 1][k + 1] = &(cube[i][j][k]);
            }
        }
    }
}
void print_top() {
    for (int j = 0; j < 3; ++j) {
        cout << cube[UP][j] << '\n';
    }
}

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

    cin >> N;
    init_pointer();
    for (int i = 0; i < N; ++i) {
        cin >> C;
        init();
        for (int j = 0; j < C; ++j) {
            cin >> input;
            spin_cube(input[0], input[1] == '+');
        }
        print_top();
    }
}

 

 

※ 오류나 개선점이 있다면 알려주세요 :) 신속히 수정하겠습니다.