https://www.acmicpc.net/problem/12100
문제
2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.
이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)
이 문제에서 다루는 2048 게임은 보드의 크기가 N×N 이다. 보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.
출력
최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.
4가지 방향으로 총 5번을 움직 일 수 있으므로 4^5 가지 경우의 수가 있다. 1024가지 정도이기 때문에 모든 경우를 돌려봐도 될 것 같았다. 5번 이내이긴 하지만 움직임을 통해 값이 줄어들지는 않으므로 5번을 무조건 진행한다.
choose 함수 -> 움직일 방향 5번을 정한다.
simul 함수 -> 5번 move 호출 후 find_max 호출
move 함수 -> 한 방향으로 mat 움직이기
find_max 함수 -> mat에서 최대값 찾기
move 함수를 자세히 설명하자면
1. 한줄을 스캔해서 일차원 배열 arr에 저장한다.
2. arr를 규칙에 의해 더한다.
규칙 : 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다.
3. 생성된 arr를 다시 mat에 저장한다.
#include <iostream> | |
#include <vector> | |
#include <cstring> | |
using namespace std; | |
enum {RIGHT,DOWN,LEFT,UP}; | |
int N,ans = 0; | |
int org_mat[21][21]; | |
int mat[21][21]; | |
int arr[21]; | |
int choice[5]; | |
void update_max(){ | |
for(int i = 0 ; i < N ;i++){ | |
for(int j = 0 ; j < N ;j++){ | |
if(mat[i][j] > ans) | |
ans = mat[i][j]; | |
} | |
} | |
} | |
void set_arr(int dir, int k){ | |
int idx = 0; | |
memset(arr,0,sizeof(arr)); | |
if(dir == RIGHT){ | |
for(int i = N - 1 ; i >= 0; i--){ | |
if(mat[k][i]){ | |
arr[idx++] = mat[k][i]; | |
} | |
} | |
} | |
else if (dir == DOWN){ | |
for(int i = N - 1 ; i >= 0 ;i--){ | |
if(mat[i][k]) | |
arr[idx++] = mat[i][k]; | |
} | |
} | |
else if (dir == LEFT){ | |
for(int i = 0 ; i < N ;i++){ | |
if(mat[k][i]) | |
arr[idx++] = mat[k][i]; | |
} | |
} | |
else if (dir == UP){ | |
for(int i = 0 ; i < N ;i++){ | |
if(mat[i][k]) | |
arr[idx++] = mat[i][k]; | |
} | |
} | |
} | |
void set_line(int dir, int k){ | |
int temp[21] = {0}; | |
int idx = 0; | |
for(int i = 0 ; i < N ;i++){ | |
if(arr[i]) temp[idx++] = arr[i]; | |
} | |
if(dir == RIGHT ){ | |
for(int i = N - 1 ; i >= 0; i--){ | |
mat[k][i] = temp[i]; | |
} | |
} | |
else if (dir == DOWN){ | |
for(int i = N - 1 ; i >= 0 ;i--){ | |
mat[i][k] = temp[i]; | |
} | |
} | |
else if (dir == LEFT){ | |
for(int i = 0 ; i < N ;i++){ | |
mat[k][i] = temp[i]; | |
} | |
} | |
else if (dir == UP){ | |
for(int i = 0 ; i < N ;i++){ | |
mat[i][k] = temp[i]; | |
} | |
} | |
} | |
void move(int dir){ | |
for(int i = 0 ; i < N ;i++){ | |
set_arr(dir,i); | |
for(int i = 0 ; i < N ;i++){ | |
if(arr[i] == arr[i+1]){ | |
arr[i] += arr[i+1]; | |
arr[i+1] = 0; | |
} | |
} | |
set_line(dir, i); | |
} | |
} | |
void simul(){ | |
for(int i = 0 ; i < N ;i++){ | |
for(int j = 0 ; j < N ;j++) | |
mat[i][j] = org_mat[i][j]; | |
} | |
for(int i = 0 ; i < 5; i++){ | |
move(choice[i]); | |
} | |
update_max(); | |
} | |
void choose(int cnt){ | |
if(cnt == 5){ | |
simul(); | |
return ; | |
} | |
for(int k = 0 ; k < 4 ; k++){ | |
choice[cnt] = k; | |
choose(cnt + 1); | |
} | |
return; | |
} | |
int main (){ | |
ios::sync_with_stdio(0); | |
cin.tie(0); cout.tie(0); | |
cin >> N; | |
for(int i = 0 ; i < N ;i++){ | |
for(int j = 0 ; j < N ;j++){ | |
cin >> org_mat[i][j]; | |
} | |
} | |
choose(0); | |
cout << ans; | |
} |
'코딩 > 백준' 카테고리의 다른 글
[백준]21610번 마법사 상어와 비바라기 (0) | 2023.04.03 |
---|---|
[백준] 주사위굴리기 - C++ (0) | 2023.03.29 |
[백준] 14503번 로봇 청소기 - C++ (0) | 2023.03.22 |
[백준]13460번 구슬 탈출 2 (0) | 2023.03.22 |
[백준] 3109번 빵집 - C++ (0) | 2023.03.05 |