https://www.acmicpc.net/problem/12100
< 2048 (Easy) >
이 문제는 게임의 조건만 제대로 이해하면 푸는 데는 크게 어려울 것이 없는 문제이다.
< 조건 >
1. 현재 움직이려는 칸이 0인 경우는 빈칸이므로 고려하지 않는다.
2. 현재 움직이려는 칸이 이동하려는 칸이 0인 경우
ex )
2 0 4 0 2 4
0 0 0 -> 0 0 0
0 0 0 0 0 0
3. 현재 움직이려는 칸의 이동할 칸이 0 이 아닌 경우
3-1. 현재 움직이려는 칸과 이동할 칸의 값이 같은 경우
- 현재 움직인 칸을 0으로 만들어주고 이동할 칸의 값을 *2를 해준다.
- 단, 움직이려는 칸이나 이동하려는 칸이 이미 합쳐진 경우가 있다면, 그 칸은 더 이상 이동하지 못하므로 break
ex)
2 2 2 2 0 0 4 4 0 0 0 8
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
위의 예시처럼, 2 2 2 2 가 8로 하나가 되려면 2번의 이동이 필요하다.
이미 합쳐진 경우를 고려하기 위해서 게임 판 배열 사이즈만큼 배열을 하나 만들어 합쳐진 적이 있는지 체크해준다.
3-2. 현재 움직이려는 칸과 이동할 칸의 값이 다른 경우
- 움직일 수 없으므로 break.
4. 상, 하, 좌, 우를 모두 고려해보면서 재귀를 돌려준다.
상, 하, 좌, 우로 돌리기 전, 즉 for문을 들어가기 전에 배열을 그대로 복사해둔다.
5. 5번을 돌면 배열에서 가장 큰 값을 찾아 갱신해준다.
6. 재귀를 빠져나왔을 경우, 4번에서 복사해 둔 배열을 이용하여 원 상태로 돌린다.
#include <cstdio> #include <cstring> #define UP 0 #define LT 1 #define DW 2 #define RT 3 #define SIZE 21 int map[SIZE][SIZE]; int n; int iMax = -1; void copy(int (*temp)[SIZE]){ for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ temp[i][j] = map[i][j]; } } } void back(int (*temp)[SIZE]){ for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ map[i][j] = temp[i][j]; } } } void playing(int dir){ bool IsMerge[SIZE][SIZE]; memset(IsMerge, 0, sizeof(IsMerge)); if(dir == UP){ for(int i = 1; i < n ; i++){ for(int j = 0; j < n; j++){ for(int k = i; k >= 1; k--){ if(map[k][j] == 0) break; if(map[k - 1][j] == 0){ map[k - 1][j] = map[k][j]; map[k][j] = 0; } else{ if(IsMerge[k][j]) break; if(IsMerge[k - 1][j]) break; if(map[k - 1][j] != map[k][j]) break; map[k - 1][j] *= 2; map[k][j] = 0; IsMerge[k - 1][j] = true; } } } } } else if (dir == DW){ for(int i = n - 2; i >= 0; i--){ for(int j = 0; j < n; j++){ for(int k = i; k < n - 1; k++){ if(map[k][j] == 0) break; if(map[k + 1][j] == 0){ map[k + 1][j] = map[k][j]; map[k][j] = 0; } else{ if(IsMerge[k][j]) break; if(IsMerge[k + 1][j]) break; if(map[k + 1][j] != map[k][j]) break; map[k + 1][j] *= 2; map[k][j] = 0; IsMerge[k + 1][j] = true; } } } } } else if (dir == LT){ for(int i = 0; i < n; i++){ for(int j = 1; j < n; j++){ for(int k = j; k >= 1; k--){ if(map[i][k] == 0) break; if(map[i][k - 1] == 0){ map[i][k - 1] = map[i][k]; map[i][k] = 0; } else{ if(IsMerge[i][k]) break; if(IsMerge[i][k - 1]) break; if(map[i][k - 1] != map[i][k]) break; map[i][k - 1] *= 2; map[i][k] = 0; IsMerge[i][k - 1] = true; } } } } } else if (dir == RT){ for(int i = 0; i < n; i++){ for(int j = n - 2; j >= 0; j--){ for(int k = j; k < n - 1; k++){ if(map[i][k] == 0) break; if(map[i][k + 1] == 0){ map[i][k + 1] = map[i][k]; map[i][k] = 0; } else{ if(IsMerge[i][k]) break; if(IsMerge[i][k + 1]) break; if(map[i][k + 1] != map[i][k]) break; map[i][k + 1] *= 2; map[i][k] = 0; IsMerge[i][k + 1] = true; } } } } } } void solution(int num){ if(num == 5){ for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ if(map[i][j] > iMax) iMax = map[i][j]; } } return; } int temp[SIZE][SIZE]; copy(temp); for(int i=0; i<4; i++){ playing(i); solution(num + 1); back(temp); } } int main(){ scanf("%d", &n); for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ scanf("%d", &map[i][j]); if(map[i][j] > iMax) iMax = map[i][j]; } } solution(0); printf("%d\n", iMax); return 0; }
'알고리즘 > 백준 문제풀기' 카테고리의 다른 글
BOJ 백준 2644 촌수계산 (0) | 2018.12.10 |
---|---|
BOJ 백준 7569 토마토 (0) | 2018.12.09 |
BOJ 백준 1068 트리 (0) | 2018.12.08 |
BOJ 백준 9461 파도반 수열 (0) | 2018.11.21 |
BOJ 백준 13460 구슬 탈출2 콜라한캔 (0) | 2018.11.19 |