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

문제 설명
r*c
의 격자이고, 정령(골렘)들은 북쪽을 통해서 들어옴. K
명의 정령들은 골렘을 타고 숲을 탐색하는데, 골렘은 십자 모양의 구조를 가지고 있고, 중앙 칸을 포함해 5칸을 차지함. 중앙을 제외한 나머지 1칸은 출구로, 골렘에서 내릴 때에는 반드시 정해진 출구를 통해서만 내릴 수 있음. i번째로 숲을 탐색하는 골렘은 숲의 가장 북쪽에서 시작해 골렘의 중앙의 c_i열이 되도록 하는 위치에서 내려옴. 초기 골렘의 출구는 d_i
방향에 위치하고 있음.
골렘은 숲을 탐색하기 위해 다음과 같은 우선순위로 이동하는데, 더이상 움직이지 못할 때까지 다음 과정을 반복함.
- 남쪽으로 한 칸 내려감
- (1)이 안된다면, 서쪽 방향으로 회전하면서 내려감
- (2)가 안된다면, 동쪽 방향으로 회전하면서 내려감
더이상 움직일 수 없다면, 정령은 갈 수 있는 칸 중 가장 남쪽의 칸으로 이동하고 완전히 종료함.
해결 방법
- 아래로 내려갈 수 있는 공간이 있다면, 내려가기
- 그렇지 않다면 왼쪽으로 내려갈 수 있는 공간이 있다면 내려가고 골렘의 좌표값과 출구 값 변경
- 그렇지 않다면 오른쪽으로 내려갈 수 있는 공간이 있다면 내려가고 골렘의 좌표값과 출구 값 변경
- 그것도 안된다면 골렘은 더이상 내려갈 수 없음.
골렘 움직이기
for (r = 0;r <= n;r++) {
int c = gol[g].c;
if (in_bound_r(r + 2) && in_bound_c(c - 1) && in_bound_c(c + 1) && arr[r + 1][c - 1] == 0 && arr[r + 1][c + 1] == 0 && arr[r + 2][c] == 0) {
continue;
}
else {
if (in_bound_r(r - 1) && in_bound_r(r + 2) && in_bound_c(c - 2) && arr[r - 1][c - 1] == 0&& arr[r][c - 2] == 0&& arr[r + 1][c - 1] == 0&& arr[r + 1][c - 2] == 0 && arr[r + 2][c - 1] == 0) {
gol[g].c = gol[g].c - 1;
gol[g].d = gol[g].d == 0 ? 3 : gol[g].d - 1;
}
else if (in_bound_r(r - 1) && in_bound_r(r + 2) && in_bound_c(c + 2) && arr[r - 1][c + 1] == 0&& arr[r][c + 2] == 0&& arr[r + 1][c + 1] == 0&& arr[r + 1][c + 2] == 0&& arr[r + 2][c + 1] == 0) {
gol[g].c = gol[g].c + 1;
gol[g].d = (gol[g].d + 1) % 4;
}
else {
break;
}
}
}
골렘의 상단이 들어가지 못했다면, 배열을 모두 백지상태로 만들고 해당 골렘의 턴 종료.
if (r-1 <= 2) {
// 몸이 들어가지 못한 상태
for (int i = 0;i < n;i++) {
for (int j = 0;j < m;j++) {
arr[i][j] = 0;
}
}
return 0;
}
출구를 기준으로 BFS를 돌리고, 도달할 수 있는 값 중 가장 행이 큰 위치를 반환함.
queue<pair<int, int>> que;
int d = gol[g].d;
if (d == 0) {
arr[r - 1][c] = -g;
que.push({ r - 1,c });
}
else if (d == 1) {
arr[r][c + 1] = -g;
que.push({ r,c + 1 });
}
else if (d == 2) {
arr[r + 1][c] = -g;
que.push({ r + 1,c });
}
else {
arr[r][c - 1] = -g;
que.push({ r,c - 1 });
}
int cx, cy, nx, ny;
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
while (!que.empty()) {
tie(cx, cy) = 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 >= m) continue;
if (visited[nx][ny] || arr[nx][ny] == 0) continue;
if (arr[cx][cy] > 0 && abs(arr[nx][ny]) != abs(arr[cx][cy])) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
}
}
for (int i = n - 1;i >= 0;i--) {
for (int j = 0;j < m;j++) {
if (visited[i][j] == 1) {
return i - 2;
}
}
전체 코드
#include <iostream>
#include <queue>
#include <tuple>
#include <cstring>
using namespace std;
typedef struct {
int c, d; // 열, 방향 (북,동,남,서)
}_gol;
int n, m, k;
_gol gol[1002];
int arr[73][73];
int visited[73][73];
void input() {
cin >> n >> m >> k;
int c, d;
for (int i = 1;i <= k;i++) {
cin >> c >> d;
gol[i].c = c - 1;
gol[i].d = d;
}
n += 3;
}
void print_arr() {
cout << "print_arr:\\n";
for (int i = 0;i < n;i++) {
for (int j = 0;j < m;j++) {
if (arr[i][j] < 0) cout << "# ";
else cout << arr[i][j] << " ";
}
cout << "\\n";
}
cout << "\\n";
}
bool in_bound_r(int r) {
if (r < 0 || r >= n) return false;
else return true;
}
bool in_bound_c(int c) {
if (c < 0 || c >= m) return false;
return true;
}
int golem_move(int g) {
int r;
for (r = 0;r <= n;r++) {
int c = gol[g].c;
// 1. 남쪽으로 내려갈 수 있는지
// arr[r+1][c-1] && arr[r+1][c+1] && arr[r+2][c]
// 2. 왼쪽으로 회전하고 내려갈 수 있는지
// arr[r-1][c-1] && arr[r][c-2] && arr[r+1][c-1]
// arr[r+1][c-2] && arr[r+2][c-1]
// 3. 오른쪽으로 회전하고 내려갈 수 있는지
// arr[r-1][c+1] && arr[r][c+2] && arr[r+1][c+1]
// arr[r+1][c+2] && arr[r+2][c+1]
if (in_bound_r(r + 2) && in_bound_c(c - 1) && in_bound_c(c + 1) && arr[r + 1][c - 1] == 0 && arr[r + 1][c + 1] == 0 && arr[r + 2][c] == 0) {
continue;
}
else if (r == 0) {
if (in_bound_r(r + 2) && in_bound_c(c - 2) && arr[r][c - 2] == 0 && arr[r + 1][c - 1] == 0 && arr[r + 1][c - 2] == 0 && arr[r + 2][c - 1] == 0) {
gol[g].c = gol[g].c - 1;
gol[g].d = gol[g].d == 0 ? 3 : gol[g].d - 1;
}
else if (in_bound_r(r + 2) && in_bound_c(c + 2) && arr[r][c + 2] == 0 && arr[r + 1][c + 1] == 0 && arr[r + 1][c + 2] == 0 && arr[r + 2][c + 1] == 0) {
gol[g].c = gol[g].c + 1;
gol[g].d = (gol[g].d + 1) % 4;
}
else {
break;
}
}
else {
if (in_bound_r(r - 1) && in_bound_r(r + 2) && in_bound_c(c - 2) && arr[r - 1][c - 1] == 0&& arr[r][c - 2] == 0&& arr[r + 1][c - 1] == 0&& arr[r + 1][c - 2] == 0 && arr[r + 2][c - 1] == 0) {
gol[g].c = gol[g].c - 1;
gol[g].d = gol[g].d == 0 ? 3 : gol[g].d - 1;
}
else if (in_bound_r(r - 1) && in_bound_r(r + 2) && in_bound_c(c + 2) && arr[r - 1][c + 1] == 0&& arr[r][c + 2] == 0&& arr[r + 1][c + 1] == 0&& arr[r + 1][c + 2] == 0&& arr[r + 2][c + 1] == 0) {
gol[g].c = gol[g].c + 1;
gol[g].d = (gol[g].d + 1) % 4;
}
else {
break;
}
}
}
if (r-1 <= 2) {
// 몸이 들어가지 못한 상태
for (int i = 0;i < n;i++) {
for (int j = 0;j < m;j++) {
arr[i][j] = 0;
}
}
return 0;
}
memset(visited, 0, sizeof(visited));
int c = gol[g].c;
arr[r][c] = g;
arr[r - 1][c] = g;
arr[r + 1][c] = g;
arr[r][c - 1] = g;
arr[r][c + 1] = g;
memset(visited, 0, sizeof(visited));
visited[r][c] = 1;
visited[r - 1][c] = 1;
visited[r + 1][c] = 1;
visited[r][c - 1] = 1;
visited[r][c + 1] = 1;
// 북동남서
queue<pair<int, int>> que;
int d = gol[g].d;
if (d == 0) {
arr[r - 1][c] = -g;
que.push({ r - 1,c });
}
else if (d == 1) {
arr[r][c + 1] = -g;
que.push({ r,c + 1 });
}
else if (d == 2) {
arr[r + 1][c] = -g;
que.push({ r + 1,c });
}
else {
arr[r][c - 1] = -g;
que.push({ r,c - 1 });
}
int cx, cy, nx, ny;
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
while (!que.empty()) {
tie(cx, cy) = 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 >= m) continue;
if (visited[nx][ny] || arr[nx][ny] == 0) continue;
if (arr[cx][cy] > 0 && abs(arr[nx][ny]) != abs(arr[cx][cy])) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
}
}
/*
cout << "visited:\\n";
for (int i = 0;i < n;i++) {
for (int j = 0;j < m;j++) {
cout << visited[i][j] << " ";
}
cout << "\\n";
}
*/
for (int i = n - 1;i >= 0;i--) {
for (int j = 0;j < m;j++) {
if (visited[i][j] == 1) {
return i - 2;
}
}
}
}
void solve() {
int result = 0;
for (int g = 1;g <= k;g++) {
result += golem_move(g);
// print_arr();
}
cout << result;
}
void init() {
for (int i = 0;i < n;i++) {
for (int j = 0;j < m;j++) {
arr[i][j] = 0;
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
// freopen("sample_input.txt", "r", stdin);
input();
init();
solve();
return 0;
}