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

문제 설명
5*5
형태의 배열이 있음. 해당 배열에는 1-7
의 값이 있음.
3*3
의 격자 선택 및 회전5*5
형태의 배열 내에서3*3
의 격자를 선택해야 함. 해당 격자를90도
,180도
,270도
회전이 가능함. 격자 선택의 순서는 다음과 같음 : (1) 유물 1차 획득 최대화 → (2) 회전한 각도가 가장 작은 방법 → (3) 열이 가장 작은 구간, 열이 같다면 행이 가장 적은 구간- 유물 획득회전 후, 3개 이상 연결되어 있는 값들을 제거하고, 제거한 값들을 유적 벽면에 적혀있는 숫자들을 집어 넣음. 유적 벽면에 적는 순서는 다음과 같음 : (1) 열 번호가 가장 작은 순 → (2) 행 번호가 가장 큰 순
- 유물 연쇄 획득유물이 새로 생겨난 후에, 3개 이상 연결되어 있는 값들이 없을 때까지 획득 및 제거를 반복함.
탐사 진행 - 유물 연쇄 획득을 K
번의 턴에 걸쳐 진행함.
해결 방법
유물 획득회전한 배열을 기반으로, 유물 획득 - 유물 생성을 반복해줌. 해당 결과에서 얻는 값들을 cur_cnt
에 저장해줌.
while (true) {
int cur_val = get_treasure();
cur_cnt += cur_val;
if (cur_val == 0) break;
write_val();
}
유물 획득 코드. 1번의 chk_treasure
과 로직이 비슷함.
int get_treasure() {
memset(visited, 0, sizeof(visited));
int cx, cy, nx, ny;
int ret = 0;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (visited[x][y]) continue;
queue<pair<int, int>> que;
vector<pair<int, int>> pop_list;
que.push({ x,y });
pop_list.push_back({ x,y });
visited[x][y] = 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 >= 5 || ny >= 5) continue;
if (visited[nx][ny]) continue;
if (arr[cx][cy] != arr[nx][ny]) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
pop_list.push_back({ nx,ny });
}
}
if (pop_list.size() >= 3) {
ret += pop_list.size();
for (int i = 0;i < pop_list.size();i++) {
arr[pop_list[i].first][pop_list[i].second] = 0;
}
}
}
}
return ret;
}
유물 작성
void write_val() {
for (int i = 0;i < 5;i++) {
for (int j = 4;j >= 0;j--) {
if (arr[j][i] == 0) {
arr[j][i] = wait_list[list_cur];
list_cur++;
}
}
}
}
3*3 격자 선택 및 회전문제 설명에는 중간을 골랐으나, 나는 좌측 좌상단을 기준으로 골랐음. 좌측 좌상단을 고르고, 각각 90도, 180도, 270도의 회전 결과를 chk[x][y][t]
에 넣어줌.
memset(chk, 0, sizeof(chk));
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
get_val(i, j);
set_arr();
}
}
...
void get_val(int x, int y) {
// 1. x ... x+2, y ... y+2를 r번 회전
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
tmp_arr[i][j] = arr[i + x][j + y];
}
}
for (int t = 0;t < 3;t++) {
rotate();
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
arr[i + x][j + y] = tmp_arr[i][j];
}
}
chk[x][y][t] = chk_treasure();
}
return;
}
회전한 배열에서 얻을 수 있는 값들을 저장하는 함수. BFS를 사용하였음.
// chk 배열에 1차 획득의 결과를 저장 (get_val 보조)
int chk_treasure() {
memset(visited, 0, sizeof(visited));
int cx, cy, nx, ny;
int ret = 0;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (visited[x][y]) continue;
int cnt = 1;
queue<pair<int, int>> que;
que.push({ x,y });
visited[x][y] = 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 >= 5 || ny >= 5) continue;
if (visited[nx][ny]) continue;
if (arr[cx][cy] != arr[nx][ny]) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
cnt++;
}
}
if (cnt >= 3) ret += cnt;
}
}
return ret;
}
전체 코드
#include <iostream>
#include <queue>
#include <cstring>
#include <tuple>
using namespace std;
int k, m;
int org[6][6];
int arr[6][6];
int wait_list[301];
int list_cur = 0;
int chk[4][4][3];
int tmp_arr[3][3];
// 입력
void input() {
cin >> k >> m;
for (int i = 0;i < 5;i++) {
for (int j = 0;j < 5;j++) {
cin >> arr[i][j];
org[i][j] = arr[i][j];
}
}
for (int i = 0;i < m;i++) {
cin >> wait_list[i] ;
}
}
// arr를 org으로 원상복구
void set_arr() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
arr[i][j] = org[i][j];
}
}
}
// 회전
void rotate() {
int ttmp[3][3];
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
ttmp[i][j] = tmp_arr[3 - j - 1][i];
}
}
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
tmp_arr[i][j] = ttmp[i][j];
}
}
}
int visited[6][6];
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
// chk 배열에 1차 획득의 결과를 저장 (get_val 보조)
int chk_treasure() {
memset(visited, 0, sizeof(visited));
int cx, cy, nx, ny;
int ret = 0;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (visited[x][y]) continue;
int cnt = 1;
queue<pair<int, int>> que;
que.push({ x,y });
visited[x][y] = 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 >= 5 || ny >= 5) continue;
if (visited[nx][ny]) continue;
if (arr[cx][cy] != arr[nx][ny]) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
cnt++;
}
}
if (cnt >= 3) ret += cnt;
}
}
return ret;
}
// x,y위치의 배열을 회전 및 결과 넣어주기
void get_val(int x, int y) {
// 1. x ... x+2, y ... y+2를 r번 회전
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
tmp_arr[i][j] = arr[i + x][j + y];
}
}
for (int t = 0;t < 3;t++) {
rotate();
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
arr[i + x][j + y] = tmp_arr[i][j];
}
}
chk[x][y][t] = chk_treasure();
}
return;
}
// tx, ty, tr에 회전, 인덱스저장
void rotate_arr() {
memset(chk, 0, sizeof(chk));
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
get_val(i, j);
set_arr();
}
}
int val = -1;
// 획득 - 각도 - 열 - 행
int tr, tx, ty;
for (int r =0;r < 3;r++) {
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
if (chk[j][i][r] > val) {
val = chk[j][i][r];
tx = j, ty = i, tr = r;
}
}
}
}
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
tmp_arr[i][j] = arr[i + tx][j + ty];
}
}
for (int t = 0;t <= tr;t++) {
rotate();
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
arr[i + tx][j + ty] = tmp_arr[i][j];
}
}
}
}
int get_treasure() {
memset(visited, 0, sizeof(visited));
int cx, cy, nx, ny;
int ret = 0;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (visited[x][y]) continue;
queue<pair<int, int>> que;
vector<pair<int, int>> pop_list;
que.push({ x,y });
pop_list.push_back({ x,y });
visited[x][y] = 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 >= 5 || ny >= 5) continue;
if (visited[nx][ny]) continue;
if (arr[cx][cy] != arr[nx][ny]) continue;
visited[nx][ny] = 1;
que.push({ nx,ny });
pop_list.push_back({ nx,ny });
}
}
if (pop_list.size() >= 3) {
ret += pop_list.size();
for (int i = 0;i < pop_list.size();i++) {
arr[pop_list[i].first][pop_list[i].second] = 0;
}
}
}
}
return ret;
}
void print_arr() {
cout << "print_arr\\n";
for (int i = 0;i < 5;i++) {
for (int j = 0;j < 5;j++) {
cout << arr[i][j] << " ";
}
cout << "\\n";
}
}
void write_val() {
for (int i = 0;i < 5;i++) {
for (int j = 4;j >= 0;j--) {
if (arr[j][i] == 0) {
arr[j][i] = wait_list[list_cur];
list_cur++;
}
}
}
}
void solve() {
for (int i = 0;i < k;i++) {
int cur_cnt = 0;
rotate_arr();
while (true) {
int cur_val = get_treasure();
cur_cnt += cur_val;
if (cur_val == 0) break;
write_val();
}
if (cur_cnt == 0) break;
cout << cur_cnt << " ";
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
org[x][y] = arr[x][y];
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
// freopen("sample_input.txt", "r", stdin);
input();
solve();
return 0;
}