16985

백준 16985번

Link: 16985번: Maaaaaaaaaze


문제 설명

아아아아아아아아주 지저분한 형태의 BFS 문제다.

예전 삼성 코딩테스트 볼때부터 큐브문제는 정말 싫었는데, 이문제는 큐브 돌리기에 BFS까지 추가된 형태.

생각보다 푸는방법은 간단했다.

우선 입력을 받고 나서, 큐브의 각 층을 회전시킬 수 있는 모든 경우에 대해 회전시킨다.

그 다음, 회전된 각 층을 순열을 통해 재배열한다.

이렇게 재배열까지 완료한 지도를 BFS를 통해 탐색하고 최단거리를 찾으면 되는 문제다.

풀어보고 나니 모든 경우 다 따지고 BFS 돌린다는 단순한 풀이인데, 구현이 좀 많이 복잡한편이다.

회전하는 모든 경우 따질때 5중 for문을 쓰는데, 이걸 써도 통과가 될까 했는데 되더라.

아주 단순무식하게 모든 경우를 빠짐없이 따져보면 결과가 잘 나오고, 시간초과에 대해서도 딱히 걱정할필요가 없는 문제였다.

코드가 좀 기니 읽는데 주의할것…


정답 코드

//
// Created by Keith_Lee on 25/03/2019.
//

#include <iostream>
#include <queue>
#include <vector>
#include <string.h>
#include <algorithm>

using namespace std;

struct Point{
    int z, x, y;
};

int map[5][5][5] = {0, };
int setMap[5][5][5] = {0, };

int dx[] = {0, 0, 0, 0, 1, -1};
int dy[] = {0, 0, 1, -1, 0, 0};
int dz[] = {1, -1, 0, 0, 0, 0};

int result = 99999999;

void rotate(int partIndex, int degree){ // 몇층을 몇도로 돌릴것인가
    if(degree == 0){
        return;
    }

    int temp[5][5] = {0, };
    memcpy(temp, setMap[partIndex], sizeof(int) * 25);

    if(degree == 1){ // 오른쪽으로 90도
        for(int i=0; i<5; i++){
            for(int j=0; j<5; j++){
                setMap[partIndex][i][j] = temp[4-j][i];
            }
        }
    }
    else if(degree == 2){ // 오른쪽으로 180도
        for(int i=0; i<5; i++){
            for(int j=0; j<5; j++){
                setMap[partIndex][i][j] = temp[4-i][4-j];
            }
        }
    }
    else if(degree == 3){ // 오른쪽으로 270도
        for(int i=0; i<5; i++){
            for(int j=0; j<5; j++){
                setMap[partIndex][i][j] = temp[j][4-i];
            }
        }
    }
}

int BFS(){
    queue<Point> Queue;
    bool visit[5][5][5] = {false, };

    Queue.push({0, 0, 0});
    visit[0][0][0] = true;
    int distance = 0;

    while(!Queue.empty()){
        vector<Point> points;

        while(!Queue.empty()){
            points.push_back(Queue.front());
            Queue.pop();
        }

        for(int v=0; v<points.size(); v++){
            int currentZ = points[v].z;
            int currentX = points[v].x;
            int currentY = points[v].y;

            if(currentZ == 4 && currentX == 4 && currentY == 4){
                return distance;
            }

            for(int i=0; i<6; i++){
                int nextZ = currentZ + dz[i];
                int nextX = currentX + dx[i];
                int nextY = currentY + dy[i];

                if(nextX >= 0 && nextX < 5 && nextY >= 0 && nextY < 5 && nextZ >= 0 && nextZ < 5){
                    if(!visit[nextZ][nextX][nextY] && setMap[nextZ][nextX][nextY] == 1){
                        visit[nextZ][nextX][nextY] = true;
                        Queue.push({nextZ, nextX, nextY});
                    }
                }
            }
        }

        distance++;
    }

    return -1;
}

int main(){
    for(int i=0; i<5; i++){
        for(int j=0; j<5; j++){
            for(int k=0; k<5; k++){
                cin >> map[i][j][k];
            }
        }
    }

    vector<int> perm = {0, 1, 2, 3, 4};

    do{
        for(int i=0; i<4; i++){
            for(int j=0; j<4; j++){
                for(int k=0; k<4; k++){
                    for(int l=0; l<4; l++){
                        for(int m=0; m<4; m++){
                            for(int n=0; n<5; n++){
                                memcpy(setMap[n], map[perm[n]], sizeof(int) * 25);
                            } // 바꾼 맵 초기화: 순열로 순서 배정

                            rotate(0, i);
                            rotate(1, j);
                            rotate(2, k);
                            rotate(3, l);
                            rotate(4, m);
                            // 각층 회전

                            if(setMap[0][0][0] == 1 && setMap[4][4][4] == 1){
                                int temp = BFS();

                                if(temp > 0 && result > temp){
                                    result = temp;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    while(next_permutation(perm.begin(), perm.end()));

    if(result == 99999999){
        result = -1;
    }
    cout << result << '\n';

    return 0;
}