[12100] 2048(Easy)
풀이
제가 제일 못하는 구현 문제입니다. 그래도 나름 깔끔하게 짜서 결국 통과 받았습니다. 시험장에서 풀었다면 못풀었을 것 같네요..
상하좌우로 기울일 때 배열을 읽는 방향이 중요합니다. 배열이 아래와 같다면
- 1 2 3
 - 4 5 6
 - 7 8 9
 
왼쪽으로 기울일 때는 right stack에 3 2 1 순서대로 넣습니다. 1이 top입니다. 그리고 left stack으로 문제의 조건을 만족하면서 옮깁니다. 그리고 이를 다시 배열에 덧씌우는 과정을 진행합니다. stack을 사용하다보니 idx를 적을 때 조금 복잡한 부분이 있습니다.
- (0,0) (0,1) (0,2)
 - (1,0) (1,1) (1,2)
 - (2,0) (2,1) (2,2)
 
오른쪽으로 기울일 때는 (0,0),(0,1),(0,2) 값을 순서대로 right에 넣고 문제의 조건을 만족하면서 left stack에 넣습니다. 그리고 left에서 다시 배열에 저장할 때는 저장되는 배열의 좌표를 잘 생각해서 해야합니다.
stack의 이름이 left와 right 인 이유는 제가 노트에 그림을 그려서 해볼 때 왼쪽 오른쪽에 그렸기 때문입니다.
이 문제에서는
- 완전탐색 dfs를 깔끔하게 짜는 방법
 - 두 개의 배열을 계속해서 사용할 때 깔끔하게 하는 방법
 
을 공부할 수 있었습니다. PASS를 받고나니 좋은 문제처럼 보이네요 ㅎㅎㅎ.
코드
#include <cstdio>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX 20
#define LEFT 0
#define RIGHT 1
#define UP 2
#define DOWN 3
int n = 0;
int map[MAX][MAX];
int ans = 0;
void move(stack<pair<int, bool> > &left, stack<int> &right) {
	while (!right.empty()) {
		//오른쪽에서 하나 빼서
		int curr = right.top(); right.pop();
		//왼쪽의 top과 더할 수 있으면 더해서 left에 넣기
		if (!left.empty() && left.top().first == curr && left.top().second == false) {
			pair<int, bool> sum = make_pair(left.top().first + curr, true);
			left.pop();
			left.push(sum);
		}
		else {
			//right에서 left로 하나 옮기기
			left.push(make_pair(curr, false));
		}
	}
}
void tilt(int opt){
	stack<pair<int, bool> > left;
	stack<int> right;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			/*
			1 2 3
			4 5 6
			7 8 9
			*/
			switch (opt) {
			case RIGHT :
				if (map[i][j]) {
					//right : [ 1 2 3(top)
					//left : [ 3 2 1(top)
					right.push(map[i][j]);
					map[i][j] = 0;
				}
				break;
			case LEFT :
				if (map[i][n - 1 - j]) {
					//right : [ 3 2 1(top)
					//left : [ 1 2 3(top)
					right.push(map[i][n - 1 - j]);
					map[i][n - 1 - j] = 0;
				}
				break;
			case UP:
				if (map[n - 1 - j][i]) {
					//right : [ 7 4 1(top)
					//left : [ 1 4 7(top)
					right.push(map[n - 1 - j][i]);
					map[n - 1 - j][i] = 0;
				}
				break;
			case DOWN :
				if (map[j][i]){
					//right : [ 1 4 7(top)
					//left : [ 7 4 1(top)
					right.push(map[j][i]);
					map[j][i] = 0;
				}
				break;
			}
		}
		//이동시키기
		move(left, right);
		//다시 저장하기
		/*
		1 2 3
		4 5 6
		7 8 9
		*/
		int left_size = left.size();
		switch (opt) {
		case LEFT:
			//right : [ 3 2 1(top)
			//left : [ 1 2 3(top)
			if (left_size > 0) {
				for (int j = left_size - 1; j >= 0; j--) {
					map[i][j] = left.top().first; left.pop();
				}
			}
			break;
		case RIGHT:
			//right : [ 1 2 3(top)
			//left : [ 3 2 1(top)
			for (int j = n - left_size; j < n; j++) {
				map[i][j] = left.top().first; left.pop();
			}
			break;
		case UP:
			//right : [ 7 4 1(top)
			//left : [ 1 4 7(top)
			if (left_size > 0) {
				for (int j = left_size-1; j >= 0; j--) {
					map[j][i] = left.top().first; left.pop();
				}
			}
			break;
		case DOWN:
			//right : [ 1 4 7(top)
			//left : [ 7 4 1(top)
			for (int j = n - left_size; j < n; j++) {
				map[j][i] = left.top().first; left.pop();
			}
			break;
		}
	}
}
void findAns(void) {
	int temp = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			temp = max(temp, map[i][j]);
		}
	}
	ans = max(ans, temp);
}
void printMap(void) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			printf("%d ", map[i][j]);
		}
		printf("\n");
	}
}
void dfs(int loop) {
	if (loop == 10) {
		findAns();
		return;
	}
	int temp[MAX][MAX];
	//4방향으로 기울이기
	for (int opt = 0; opt < 4; opt++) { 
		//맵 저장
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				temp[i][j] = map[i][j];
			}
		}
		tilt(opt);
		//printMap();
		dfs(loop + 1);
		//맵 복구
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				map[i][j] = temp[i][j];
			}
		}
	}
}
int main(void) {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &map[i][j]);
		}
	}
	dfs(0);
	printf("%d\n", ans);
	return 0;
}