12100번: 2048 (Easy)
첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2
www.acmicpc.net



굉장히 복잡한 문제처럼 보이지만 N이 20이 max이고 5번 이동만 하면 되기 때문에 완전탐색 기법을 사용하여 다 해보면 된다.
map을 매번 저장해주고 [왼쪽,오른쪽,위,아래] 로 블록을 밀어주고 그 블록을 그대로 또 한번 [왼쪽,오른쪽,위,아래] 방향으로 밀어주면서 이렇게 5번을 해주고 5번이 됐을 때 블록의 최대 값을 return해주면 모든 case를 다 돌려 볼 수 있다.
1 2 3 4 5
왼쪽 -> 왼쪽 -> 왼쪽 -> 왼쪽 -> 왼쪽 => max값
왼쪽 -> 왼쪽 -> 왼쪽 -> 왼쪽 -> 오른쪽 => max값
왼쪽 -> 왼쪽 -> 왼쪽 -> 왼쪽 -> 위 => max값
왼쪽 -> 왼쪽 -> 왼쪽 -> 왼쪽 -> 아래 => max값
이런식으로 쭈욱 완전 탐색을 하는 것이다. 저렇게 위의 숫자를 count로 하여 계속해서 max값을 return해주면 정답이 나온다.
재귀에 대해 이해를 반드시 해야 풀 수 있는 문제이다.
또한 queue를 통해 2 2 2 가 있으면 2 2 2 를 넣고 앞에서 부터 2, 2 / 2 를 찾아 4 2 를 만들어 준다.
위로 민다고 치면 2 4 8인데 여기서 합칠 수 있는게 없으므로 2 4 8을 그대로 block에 저장해야 한다.
이제 코드를 보자.
#include <iostream> #include <queue> using namespace std; #define MAX_MAP 21 int map[MAX_MAP][MAX_MAP]; int N; void shift(int block[MAX_MAP][MAX_MAP], int pos) { queue<int> q; switch (pos) { //왼쪽 case 0: for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { //0이 아닌 경우에만 밀면 됨으로 0이 아닌 경우만 queue에 저장 if (block[i][j]) q.push(block[i][j]); //queue에 넣었으니 0으로 초기화 block[i][j] = 0; } int pos = 0; //q가 비어질 때 까지 while (!q.empty()) { int data = q.front(); q.pop(); //현재 block의 위치가 0이면 값을 넣어줌 (처음 case) if (block[i][pos] == 0) { block[i][pos] = data; } //현재 block의 위치와 data가 같으면 동일한 숫자가 있는 것으로 *2 해줌 (2 / 2 case) else if (block[i][pos] == data) { block[i][pos] = block[i][pos] * 2; pos++; } //다른 값이 있으면 block의 다음 위치에 (2 / 4 case) else { pos++; block[i][pos] = data; } } } break; //오른쪽 case 1: for (int i = 0; i < N; i++) { //뒤부터 -> 오른쪽으로 미는 것이기 때문에 for (int j = N - 1; j >= 0; j--) { if (block[i][j]) q.push(block[i][j]); block[i][j] = 0; } //뒤부터 집어 넣기 int pos = N - 1; while (!q.empty()) { int data = q.front(); q.pop(); if (block[i][pos] == 0) { block[i][pos] = data; } else if (block[i][pos] == data) { block[i][pos] = block[i][pos] * 2; pos--; } else { pos--; block[i][pos] = data; } } } break; //위 case 2: for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { //i, j 반대로 if (block[j][i]) q.push(block[j][i]); block[j][i] = 0; } int pos = 0; while (!q.empty()) { int data = q.front(); q.pop(); if (block[pos][i] == 0) { block[pos][i] = data; } else if (block[pos][i] == data) { block[pos][i] = block[pos][i] * 2; pos++; } else { pos++; block[pos][i] = data; } } } break; //아래 case 3: for (int i = 0; i < N; i++) { for (int j = N - 1; j >= 0; j--) { //i, j 반대로 if (block[j][i]) q.push(block[j][i]); block[j][i] = 0; } int pos = N - 1; while (!q.empty()) { int data = q.front(); q.pop(); if (block[pos][i] == 0) { block[pos][i] = data; } else if (block[pos][i] == data) { block[pos][i] = block[pos][i] * 2; pos--; } else { pos--; block[pos][i] = data; } } } break; } } int solve(int block[MAX_MAP][MAX_MAP], int count) { int maxVal = -1; if (count == 5) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (block[i][j] > maxVal) maxVal = block[i][j]; } } return maxVal; } //현재 Block을 저장해 놓을 Block선언 int copyBlock[MAX_MAP][MAX_MAP] = { 0, }; //네 방향 for (int i = 0; i < 4; i++) { //Block copy for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { copyBlock[i][j] = block[i][j]; } } //Block이동 shift(copyBlock, i); //다음 count로 넘어감 maxVal = max(maxVal,solve(copyBlock, count + 1)); } return maxVal; } int main() { cin >> N; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { cin >> map[i][j]; } } cout << solve(map, 0) << endl; }
'알고리즘 > 삼성 SW 역량 테스트 기출 문제' 카테고리의 다른 글
[C++][BOJ] 삼성 SW 역량 테스트 기출 문제 - 13458번 시험 감독 (0) | 2021.05.17 |
---|---|
[C++][BOJ] 삼성 SW 역량 테스트 기출 문제 - 3190번 뱀 (0) | 2021.05.13 |
[C++][BOJ] 삼성 SW 역량 테스트 기출 문제 - 13460번 구슬 탈출2 (0) | 2021.05.11 |
[C++][BOJ] 삼성 SW 역량 테스트 기출 문제 - 14889번 스타트와 링크 (0) | 2021.05.08 |
[C++][BOJ] 삼성 SW 역량 테스트 기출 문제 - 14888번 연산자 끼워넣기 (0) | 2021.05.03 |
댓글