Gi-Log

백준(BOJ) 16985 Maaaaaaaaaze C++ 풀이 본문

알고리즘 BOJ

백준(BOJ) 16985 Maaaaaaaaaze C++ 풀이

돌잔 2021. 8. 18. 20:51

문제 링크: https://www.acmicpc.net/problem/16985

 

16985번: Maaaaaaaaaze

첫째 줄부터 25줄에 걸쳐 판이 주어진다. 각 판은 5줄에 걸쳐 주어지며 각 줄에는 5개의 숫자가 빈칸을 사이에 두고 주어진다. 0은 참가자가 들어갈 수 없는 칸, 1은 참가자가 들어갈 수 있는 칸을

www.acmicpc.net

풀이에 이용된 알고리즘: BFS, 순열(DFS), Brute Force

 

삼성 전자 코딩 테스트 기출 문제 풀이를 진행했거나 최근 bfs, dfs 등을 공부하는 사람에게는 익숙한 미로 탐색 유형이다.

 

아... 미로 탐색 유형이 익숙하다는 것이고, 16985 문제의 경우는 익숙하지 않은 미로 탐색처럼 느껴질 수 있다고 생각된다.

 

일단 단순히 미로를 탐색하는 것이 아니라, 미로를 제작도 우리가 해야한다....

 

그리고 제작된 미로를 탐색하여 최단 거리를 구하는데, 각 미로별 최단 거리 중에서 가장 작은 값을 출력하는 것이 이 문제의 목표이다.

 

따라서 제작 가능한 모든 미로를 만들고, 각각에 대해서 최단 거리 탐색 즉 bfs를 적용하는 brute force 방법으로 문제를 풀었다

 

미로 제작은, 미리 준비된 5개의 판의 순서를 임의로 정해서 쌓아주면(3차원 틀에 판을 삽입하는 것으로 생각했다.) 3차원 미로가 완성된다. --> select_arr 함수 구현

 

이 때, 판은 시계 방향 또는 반시계 방향 90도 단위로 자유롭게 회전이 가능하다. --> rotate_arr 함수 구현

 

모든 경우의 미로 제작을 위해서 상기 내용을 dfs로 구현한다.

 

그리고 미로 탐색은 일반적인 2차원 미로에서 x y 방향뿐 아니라, z축 방향을 고려해야하므로 dz, dx, dy를 다음과 같이 구현하였다.

 

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

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

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

 

dfs로 5개의 판 모두를 선택하여 3차원 틀에 넣어주면 즉, 5개의 판을 선택한 후에는(selected 배열 이용) 시작점 (1, 1, 1)에서 도착점 (5, 5, 5)까지의 최단 거리를 파악하고 현재 ans보다 작은 값이라면 갱신하도록 한다.

 

(이 때, 시작점 (1, 1, 1)이 이동 가능한 칸인지도 꼭 확인해주어야 한다!)

 

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* BOJ 16985 Maaaaaaaaaze */
#include <iostream>
#include <functional>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <string.h>
#include <vector>
 
using namespace std;
 
typedef long long ll;
 
int maze[6][6][6], parts[6][6][6], selected[6], visited[6][6][6];
int dz[] = {0000-11};
int dx[] = {-101000};
int dy[] = {010-100};
const int INF = 1e9;
int ans = INF;
 
void rotate_arr(int h_idx) // 90도 시계 방향 회전
{
    int tmp[6][6];
    for (int i = 1; i <= 5; i++)
        for (int j = 5; j > 0; j--)
            tmp[j][5 - i + 1= maze[h_idx][i][j];
 
    for (int i = 1; i <= 5; i++)
        for (int j = 1; j <= 5; j++)
            maze[h_idx][i][j] = tmp[i][j];
}
 
void select_arr(int h_idx, int part_num) // '판'을 선택하여 미로의 h_idx 층에 삽입
{
    for (int i = 1; i <= 5; i++)
        for (int j = 1; j <= 5; j++)
            maze[h_idx][i][j] = parts[part_num][i][j];
}
 
typedef struct NODE
{
    int x, y, z;
    NODE(int _z, int _x, int _y)
    {
        z = _z, x = _x, y = _y;
    }
} NODE;
 
int bfs()
{
    memset(visited, 0xffsizeof(visited));
    queue<NODE> q;
    q.push({111});
    visited[1][1][1= 0;
 
    while (!q.empty())
    {
        int z = q.front().z;
        int x = q.front().x;
        int y = q.front().y;
        q.pop();
 
        for (int i = 0; i < 6; i++)
        {
            int nz = z + dz[i], nx = x + dx[i], ny = y + dy[i];
            if (visited[nz][nx][ny] == -1 && maze[nz][nx][ny] == 1)
            {
                q.push({nz, nx, ny});
                visited[nz][nx][ny] = visited[z][x][y] + 1;
            }
        }
    }
 
    return visited[5][5][5];
}
 
void dfs(int h_idx)
{
    if (h_idx > 5)
    {
        // 미로 탐색 시작
        // 최소값 갱신
        if (maze[1][1][1== 1// (1, 1, 1)이 0이면 아예 미로 탐색 시작 조차 불가능
        {
            int move_cnt = bfs(); // (5, 5, 5)까지 탐색 진행
            if (move_cnt != -1)
                ans = min(ans, move_cnt);
        }
        return;
    }
 
    for (int i = 1; i <= 5; i++)
    {
        if (!selected[i])
        {
            selected[i] = true;   // i번째 '판' 선택
            select_arr(h_idx, i); // 미로의 h_idx 층에 i번째 '판'을 삽입
 
            for (int d = 0; d < 4; d++// 회전
            {
                rotate_arr(h_idx); // 미로의 h_idx 층을 90도 시계 방향 회전
                dfs(h_idx + 1);
            }
 
            selected[i] = false;
        }
    }
}
 
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
 
    freopen("input.txt""r", stdin);
 
    int num = 1;
    for (int i = 1; i <= 5; i++)
        for (int j = 1; j <= 5; j++)
            for (int k = 1; k <= 5; k++)
                cin >> parts[i][j][k];
 
    dfs(1);
 
    cout << ((ans == INF) ? -1 : ans) << endl;
 
    return 0;
}
cs

 

Comments