hotamul의 개발 이야기

[Algorithm][C++] BOJ 12100 2048(Easy) 본문

myt-algorithm-practice/Samsung SW Certi Adv

[Algorithm][C++] BOJ 12100 2048(Easy)

hotamul 2021. 10. 24. 22:09

url: https://www.acmicpc.net/problem/12100

 

12100번: 2048 (Easy)

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

www.acmicpc.net

 

풀이 핵심

1. 완전 탐색 문제 (Bruth Force / Back Tracking)

 

2. map을 반시계 방향으로 (시계 방향인지 반시계 방향인지는 중요하지 않음) 회전시키는 함수와 위로 이동시키는 함수를 구현한다. (상 하 좌 우로 이동시키는 함수를 각각 구현하기는 번거롭기 때문)

 

3. 문제에서 가장 중요한 것은 이동시키는 함수를 어떻게 구현하는 것이냐 이다.

  • "이미 합쳐진 숫자이므로 합쳐지면 안 돼!" 를 표시할 수 있는 flag와 이동시켜야 하는 위치를 나타내는 target을 이용했다. 
  • flag가 true이면 합쳐질 수 있어라는 뜻이고 false이면 합쳐질 수 없어 라는 뜻이다.
  • 따라서 flag가 true이고 현재 이동할 위치에 있는 숫자 (temp[target][c]) 와 이동시켜야 하는 숫자 (map[r][c]) 가 같으면 더해 주는 방식으로 구현했다. (temp[target][c] += map[r][c]) 그리고 더 이상 합쳐지면 안 되므로 flag를 false로 바꿔준다.
  • 위의 조건을 만족하지 않으면 target을 증가시키고 이동할 숫자 (map[r][c])를 이동할 위치에 이동시킨다. (temp[++target][c] = map[r][c])

 

4. 재귀 함수 형식의 solve를 통해 완전 탐색할 수 있도록 했다.

 

코드

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

int N, ans;

struct BOARD {
	int map[20][20];

	int get_max() { // 최대 구하는 함수
		int ret = 0;
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				if (ret < map[r][c]) {
					ret = map[r][c];
				}
			}
		}
		return ret;
	}

	void rotate() { // 90도 회전
		int temp[20][20];
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				temp[r][c] = map[c][N - r - 1];
			}
		}
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				map[r][c] = temp[r][c];
			}
		}
	}

	void up() { // 위로 이동시키는 함수
		int temp[20][20] = { 0, };
		for (int c = 0; c < N; c++) {
			bool flag = false; // 이미 합쳐진 숫자이므로 더하면 안 돼!
			int target = -1; // 숫자가 이동할 위치
			for (int r = 0; r < N; r++) {
				if (map[r][c] == 0) continue; // 이동 시킬 숫자가 0이라면 continue
				/*flag가 true이고 이동할 위치의 숫자가 이동시킬 숫자와 같을 때 더한다.
				여기서 target != -1 은 segmentation fault를 피하기 위해 넣었다*/
				if (flag && target != -1 && temp[target][c] == map[r][c]) {
					temp[target][c] += map[r][c];
					flag = false; // 이제 이 숫자는 더 이상 합쳐질 수 없어!
				}
				// 위 조건이 아니라면
				else {
					temp[++target][c] = map[r][c];
					flag = true; // 합쳐질 수 있어
				}
			}
		}
		for (int r = 0; r < N; r++) {
			for (int c = 0; c < N; c++) {
				map[r][c] = temp[r][c];
			}
		}
	}
};

void solve(BOARD cur, int cnt) {
	if (cnt == 5) {
		int candi = cur.get_max();
		if (ans < candi) ans = candi;
		return;
	}

	for (int dir = 0; dir < 4; dir++) {
		BOARD next = cur;
		next.up();
		solve(next, cnt + 1);
		cur.rotate();
	}
}

int main() {
	BOARD board;
	scanf("%d", &N);
	for (int r = 0; r < N; r++) {
		for (int c = 0; c < N; c++) {
			scanf("%d", &board.map[r][c]);
		}
	}
	solve(board, 0);
	printf("%d", ans);
	return 0;
}
Comments