미지의 공간 탈출 [2024-하반기 오전 1번 문제]
문제 링크
삼성 코딩테스트 기출 문제: 미지의 공간 탈출 - 코드트리
주요 IT 기업의 코딩테스트 기출 문제를 연습하며 실전 감각을 키우세요. 취업 합격률을 높이는 필수 연습 과정입니다.

문제 설명
N*N
의 크기의 배열에 M*M*M
크기의 정육면체가 있음. 빈 공간은 0
, 장애물은 1
, 타임머신(자신)은 2
, 정육면체의 위치는 3
, 탈출구는 4
로 표현됨. 또한 N*N
의 배열에는 F
개의 확산되는 시간 이상 현상(불)이 존재함. (r_i,c_i)
에서 시작해서 매 v_i
의 배수 턴마다 방향 d_i
로 한 칸씩 확산됨. 해당 미로를 탈출할 수 있는 최소 시간 구하기.
해결 방법
탈출 계산정육면체에 탈출하는 시간동안에는, 움직여주지 않고, 막 탈출 했을 시, 탈출 가능한 위치에 이동할 수 있는 지 확인. 이동할 수 없으면 -1을 반환. 탈출 시에는 queue
를 사용하여 초마다 가능한 경로를 저장하고 탈출 시, 걸린 시간을 반환함.
if (t < escape_maze_cnt) continue;
else if (t == escape_maze_cnt) {
if (arr[smx][smy] == 1) return -1;
que.push({ smx,smy,t });
}
else {
queue<tuple<int, int, int>> tmp_que;
int cx, cy,ct, nx, ny;
if (que.empty()) return -1;
while (!que.empty()) {
tie(cx, cy, ct) = que.front();
que.pop();
for (int i = 0;i < 4;i++) {
nx = cx + dx[i], ny = cy + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
if (arr[nx][ny] == 4) {
t1 = nx, t2 = ny;
parent_arr[nx][ny] = { cx,cy };
return ct + 1;
}
if (arr[nx][ny] != 0 || visited_arr[nx][ny]) continue;
visited_arr[nx][ny] = 1;
parent_arr[nx][ny] = { cx,cy };
tmp_que.push({ nx,ny,ct + 1 });
}
}
swap(tmp_que, que);
}
불 확산시간이 v의 배수일 때, 확산시키고 위치를 이동.
for (int i = 0;i < f;i++) {
if (t >= fire[i].v && t % fire[i].v == 0) {
int nx, ny;
nx = fire[i].x + dx[fire[i].d], ny = fire[i].y + dy[fire[i].d];
if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
if (arr[nx][ny] != 0 && arr[nx][ny] != 2) continue;
arr[nx][ny] = 2;
fire[i].x += dx[fire[i].d], fire[i].y += dy[fire[i].d];
}
}
정육면체 탈출정육면체에는 밑면을 제외한 5개의 면이 있고, 각 면마다 이어져있기 때문에, adjust
라는 새로운 배열을 만들어서 다른 면으로 갈 때 이어질 수 있도록 하는 배열을 만듦. 5번째 인덱스는 N*N
크기의 배열로 탈출 시의 좌표로 작성하였음.
tuple<int,int,int> adjust[5][11][11][4];
void init() {
for (int i = 0;i < m;i++) {
adjust[0][0][i][3] = { 4,i,m - 1 - i };
adjust[0][i][m - 1][0] = {3,i,0};
adjust[0][m - 1][i][2] = { 5,dsx + (m - 1) - i,dsy + m };
adjust[0][i][0][1] = { 4,m - 1 - i,m - 1 };
}
for (int i = 0;i < m;i++) {
adjust[1][0][i][3] = { 4,i,0 }; // 좌측의 상단
adjust[1][i][m - 1][0] = { 2,i,0 }; // 좌측의 우측단
adjust[1][m - 1][i][2] = { 5,dsx + i,dsy - 1 }; // 좌측의 하단
adjust[1][i][0][1] = { 3,i,m - 1 }; // 좌측의 좌측단
}
for (int i = 0;i < m;i++) {
adjust[2][0][i][3] = {4,m-1,i};
adjust[2][i][m - 1][0] = { 0,i,0 };
adjust[2][m - 1][i][2] = { 5,dsx+m,dsy+i};
adjust[2][i][0][1] = { 1,i,m - 1 };
}
for (int i = 0;i < m;i++) {
adjust[3][0][i][3] = { 4,0,m - 1 - i };
adjust[3][i][m - 1][0] = { 1,i,0 };
adjust[3][m - 1][i][2] = {5,dsx-1,dsy + (m - 1) - i };
adjust[3][i][0][1] = {0,i,m-1};
}
for (int i = 0;i < m;i++) {
adjust[4][0][i][3] = { 3,0,m - 1 - i };
adjust[4][i][m - 1][0] = { 0,0,m - 1 - i };
adjust[4][m - 1][i][2] = { 2,0,i };
adjust[4][i][0][1] = { 1,0,i };
}
}
그리고 BFS
를 사용하여 정육면체를 탈출하는 조건을 구함. 탈출조건은 배열로 탈출하고(5번째 인덱스), 해당 위치에 장애물이 없을 시로 판단하였음. 해당 위치는 추후 N*N
배열 탈출을 위해 smx
,smy
에 저장함. 그리고 parent
배열을 사용하여, 얼마나 걸렸는지 판단 + 디버깅으로 사용하였음.
int visited[5][11][11];
tuple<int, int, int> parent[5][11][11];
int get_maze_path() {
queue<tuple<int, int, int>> que;
que.push({ sd,sx,sy });
visited[sd][sx][sy] = 1;
int cd, cx, cy, nd, nx, ny;
bool escape_flag = false;
while (!que.empty()) {
tie(cd, cx, cy) = que.front();
que.pop();
for (int i = 0;i < 4;i++) {
nx = cx + dx[i], ny = cy + dy[i]; nd = cd;
if (nx < 0 || ny < 0 || nx >= m || ny >= m) {
tie(nd, nx, ny) = adjust[cd][cx][cy][i];
}
if (nd == 5 && arr[nx][ny] == 0) {
smx = nx, smy = ny;
escape_flag = true;
break;
}
if (nd == 5 && arr[nx][ny]) continue;
if (visited[nd][nx][ny] || dice[nd][nx][ny]) continue;
visited[nd][nx][ny] = 1;
parent[nd][nx][ny] = { cd,cx,cy };
que.push({ nd,nx,ny });
}
if (escape_flag) break;
}
if (escape_flag == false) {
return -1;
}
int ret = 1;
int ctd, ctx, cty;
while (true) {
if (get<0>(parent[cd][cx][cy]) == sd && get<1>(parent[cd][cx][cy]) == sx && get<2>(parent[cd][cx][cy]) == sy) {
break;
}
ctd = cd, ctx = cx, cty = cy;
cd = get<0>(parent[ctd][ctx][cty]);
cx = get<1>(parent[ctd][ctx][cty]);
cy = get<2>(parent[ctd][ctx][cty]);
ret++;
}
return ret+1;
}
전체 코드
#include <iostream>
#include <tuple>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
typedef struct {
int x, y;
int d, v;
}_fire;
int n, m, f;
int arr[21][21];
int dice[5][11][11];
tuple<int,int,int> adjust[5][11][11][4];
_fire fire[11];
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
int dsx, dsy; // 미궁의 좌측상단
int sd, sx, sy; // 시작 위치
int smx, smy; // 나와서 시작 위치
void input() {
cin >> n >> m >> f;
// 미궁
bool find_dice = false;
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
cin >> arr[i][j];
if (!find_dice && arr[i][j] == 3) {
find_dice = true;
dsx = i, dsy = j;
}
}
}
// 정육면체
for (int i = 0;i < 4;i++) {
for (int j = 0;j < m;j++) {
for (int k = 0;k < m;k++) {
cin >> dice[i][j][k];
}
}
}
for (int i = 0;i < m;i++) {
for (int j = 0;j < m;j++) {
cin >> dice[4][i][j];
if (dice[4][i][j] == 2) {
sd = 4, sx = i, sy = j;
}
}
}
int x, y, d, v;
for (int i = 0;i < f;i++) {
cin >> x >> y >> d >> v;
fire[i].x = x, fire[i].y = y, fire[i].d = d, fire[i].v = v;
arr[x][y] = 2;
}
}
void init() {
for (int i = 0;i < m;i++) {
adjust[0][0][i][3] = { 4,i,m - 1 - i };
adjust[0][i][m - 1][0] = {3,i,0};
adjust[0][m - 1][i][2] = { 5,dsx + (m - 1) - i,dsy + m };
adjust[0][i][0][1] = { 4,m - 1 - i,m - 1 };
}
for (int i = 0;i < m;i++) {
adjust[1][0][i][3] = { 4,i,0 }; // 좌측의 상단
adjust[1][i][m - 1][0] = { 2,i,0 }; // 좌측의 우측단
adjust[1][m - 1][i][2] = { 5,dsx + i,dsy - 1 }; // 좌측의 하단
adjust[1][i][0][1] = { 3,i,m - 1 }; // 좌측의 좌측단
}
for (int i = 0;i < m;i++) {
adjust[2][0][i][3] = {4,m-1,i};
adjust[2][i][m - 1][0] = { 0,i,0 };
adjust[2][m - 1][i][2] = { 5,dsx+m,dsy+i};
adjust[2][i][0][1] = { 1,i,m - 1 };
}
for (int i = 0;i < m;i++) {
adjust[3][0][i][3] = { 4,0,m - 1 - i };
adjust[3][i][m - 1][0] = { 1,i,0 };
adjust[3][m - 1][i][2] = {5,dsx-1,dsy + (m - 1) - i };
adjust[3][i][0][1] = {0,i,m-1};
}
for (int i = 0;i < m;i++) {
adjust[4][0][i][3] = { 3,0,m - 1 - i };
adjust[4][i][m - 1][0] = { 0,0,m - 1 - i };
adjust[4][m - 1][i][2] = { 2,0,i };
adjust[4][i][0][1] = { 1,0,i };
}
}
int visited[5][11][11];
tuple<int, int, int> parent[5][11][11];
int get_maze_path() {
queue<tuple<int, int, int>> que;
que.push({ sd,sx,sy });
visited[sd][sx][sy] = 1;
int cd, cx, cy, nd, nx, ny;
bool escape_flag = false;
while (!que.empty()) {
tie(cd, cx, cy) = que.front();
que.pop();
for (int i = 0;i < 4;i++) {
nx = cx + dx[i], ny = cy + dy[i]; nd = cd;
if (nx < 0 || ny < 0 || nx >= m || ny >= m) {
tie(nd, nx, ny) = adjust[cd][cx][cy][i];
}
if (nd == 5 && arr[nx][ny] == 0) {
smx = nx, smy = ny;
escape_flag = true;
break;
}
if (nd == 5 && arr[nx][ny]) continue;
if (visited[nd][nx][ny] || dice[nd][nx][ny]) continue;
visited[nd][nx][ny] = 1;
parent[nd][nx][ny] = { cd,cx,cy };
que.push({ nd,nx,ny });
}
if (escape_flag) break;
}
if (escape_flag == false) {
return -1;
}
int ret = 1;
int ctd, ctx, cty;
while (true) {
if (get<0>(parent[cd][cx][cy]) == sd && get<1>(parent[cd][cx][cy]) == sx && get<2>(parent[cd][cx][cy]) == sy) {
break;
}
ctd = cd, ctx = cx, cty = cy;
cd = get<0>(parent[ctd][ctx][cty]);
cx = get<1>(parent[ctd][ctx][cty]);
cy = get<2>(parent[ctd][ctx][cty]);
ret++;
}
return ret+1;
}
int visited_arr[21][21];
pair<int, int> parent_arr[21][21];
int t1, t2;
int solve() {
int escape_maze_cnt = get_maze_path();
queue<tuple<int, int, int>> que;
visited_arr[smx][smy] = 1;
for (int t = 1;;t++) {
// 불 확산
for (int i = 0;i < f;i++) {
if (t >= fire[i].v && t % fire[i].v == 0) {
int nx, ny;
nx = fire[i].x + dx[fire[i].d], ny = fire[i].y + dy[fire[i].d];
if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
if (arr[nx][ny] != 0 && arr[nx][ny] != 2) continue;
arr[nx][ny] = 2;
fire[i].x += dx[fire[i].d], fire[i].y += dy[fire[i].d];
}
}
if (t < escape_maze_cnt) continue;
else if (t == escape_maze_cnt) {
if (arr[smx][smy] == 1) return -1;
que.push({ smx,smy,t });
}
else {
queue<tuple<int, int, int>> tmp_que;
int cx, cy,ct, nx, ny;
if (que.empty()) return -1;
while (!que.empty()) {
tie(cx, cy, ct) = que.front();
que.pop();
for (int i = 0;i < 4;i++) {
nx = cx + dx[i], ny = cy + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
if (arr[nx][ny] == 4) {
t1 = nx, t2 = ny;
parent_arr[nx][ny] = { cx,cy };
return ct + 1;
}
if (arr[nx][ny] != 0 || visited_arr[nx][ny]) continue;
visited_arr[nx][ny] = 1;
parent_arr[nx][ny] = { cx,cy };
tmp_que.push({ nx,ny,ct + 1 });
}
}
swap(tmp_que, que);
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
//freopen("sample_input.txt", "r", stdin);
input();
init();
cout << solve();
return 0;
}