Algorithm/BOJ

[백준 12100] 2048(Easy)

EVO. 2023. 5. 1. 13:29

문제 분석

 

예를 들어

2 2 2

4 4 4

8 8 8

이 주어지고

왼쪽으로 이동할때는

4 2 0

8 4 0

16 8 0

의 결과가 나와야 하는데 이러한 결과에 착안해서 해당입력에서 왼쪽으로 이동할때는 왼쪽부터 계산해야한다는 순서가 필요합니다.

좀더 도식화를 시키고 보면

a b c

d e f

h i j

왼쪽으로 이동할때

보는 순서는

(0,0)⇒(0,1):

a와 b가 같을때 (0,0) = a+b (0,1) = 0

a와 b가 다를때 (0,0) = a (0,1) = b

그러나 만약 a가 0이라면 (0,0) = b (0,1) = 0

그 다음은 (0,1)⇒(0,2):

b와 c가 같을때 (0,1) = b+c (0,2) = 0

b와 c가 다를때 (0,1) = b (0,2) = c

그러나 만약 b가 0이라면 (0,1) = c (0,2) = 0

그리고나서 이 해당 행이 끝나면

다음 행으로 가야합니다. d e f 역시 위와 같은 순서를 진행하고

다음 행 역시 그 방식으로 진행해야합니다.

이 방식이 제대로 먹히는 지 확인해보기 위해 여러가지 조건을 세웠습니다.

예시 1) 한 번의 이동에서 이미 합쳐진 블록은 또 합쳐질 수 없다

2 2 4 => 8 0 0 이 되어서는 안된다. 4 4 0 이 되야한다.

1.

4 0 4

2.

4 4 0

위 2가지 방식을 진행했을때 정상적으로 진행됨

예시 2) 똑같은 수가 세 개가 있는 경우에는 이동하려고 하는 쪽의 칸이 먼저 합쳐진다

2 2 2 => 0 2 4 가 되어서는 안되고 4 2 0 이 되야한다.

1.

4 0 2

2.

4 2 0

위 2가지 방식을 진행했을때 정상적으로 진행됨

왼쪽은 했으니

이제 오른쪽 이동이다

b와 c가 같을때 (0,2) = b+c (0,1) = 0

b와 c가 다를때 (0,2) = c (0,1) = b

그러나 만약 c가 0이라면 (0,2) = b (0,1) = 0

위로 이동

a와 d가 같을때(0,0) = a+d (1,0) = 0

a와 d가 다를때 (0,0) = a (1,0) = d

그러나 만약 a가 0이라면 (0,0) = d (1,0) = 0

이렇게 구현을 왼쪽,오른쪽,위쪽,아래쪽으로 이동했을 때의 연산을 각각 실행시키고 어느쪽이든간에 5번이 반복되어 실행되었으면 그 결과의 배열에서 최댓값을 리턴 하는 방식으로 코드를 짠다.


하지만 테스트케이스

2 2 2 2

2 2 2 2

2 2 2 2

2 2 2 2


첫줄을 보면 왼쪽으로 이동할때

=> 4 0 2 2

=> 4 2 0 2

=> 4 2 2 0

4 4 0 0

이 나와야 하는데

4 2 2 0

으로 실패


그래서 이 방식은 차용하돼 빈칸은 항상 뒤로 옮기는 방식으로 했습니다.

예를들어

2 2 2 2

=>4 0 2 2

가 나왔을때 0이 앞에 있으므로 2를 앞으로 땡겨서

4 2 2 0

으로 만들고 계산하면

4 4 0 0

으로 정상적으로 결과가 나옵니다.

즉 추가조건을 붙입니다.

a와 b가 같을때 (0,0) = a+b (0,1) = 0

\+ **(a와 b가 같을때는 무조건 0이 생기므로) 다음을 앞으로 땡긴다.**

a와 b가 다를때 (0,0) = a (0,1) = b

그러나 만약 a가 0이라면 (0,0) = b (0,1) = 0

이제 코드를 봅니다.

#include <iostream>
#include <algorithm>
using namespace std;

int N;
int arr[20][20];
int big = -1;

void 왼쪽이동()
{
	//숫자들을 모두 왼쪽정렬을 한다.
	//2의 배수의 개수를 센다 그리고 그만큼 집어넣는다.
	for (int i = 0; i < N; i++)
	{
		//2의 배수를 채워넣을 위치
		int pos = 0;

		for (int j = 0; j < N; j++)
		{
			if (arr[i][j] != 0)
			{
				arr[i][pos++] = arr[i][j];
				//pos의 위치가 그 자신인 경우는 0으로 초기화하면 안됨
				//ex) 2 0 0 2 에서 pos가 0의 위치고 j=0이면 0으로 초기화 하면 안됨
				if (pos - 1 == j)continue;

				arr[i][j] = 0;



			}
		}
	}




	for (int j = 0; j < N; j++) {
		for (int i = 0; i < N - 1; i++)
		{
			

			//a와 b가 같을때 합한다 그런데 그 위치에 0으로 만들었으므로 한칸씩 옮긴다.
			if (arr[j][i] == arr[j][i + 1]) {
				arr[j][i] = arr[j][i] + arr[j][i + 1];
				arr[j][i + 1] = 0;
				for (int k = i + 1; k < N - 1;k++)
				{
					arr[j][k] = arr[j][k + 1];

				}
				arr[j][N - 1] = 0;
			}
			else {
				//만약 a가 0이라면
				if (arr[j][i] == 0) {
					arr[j][i] = arr[j][i + 1];
					arr[j][i + 1] = 0;
				}
				else {
					continue;
				}
			}
		}
	}

}

void 오른쪽이동()
{

	//오른쪽 정렬을 한다.
	for (int i = 0; i < N; i++)
	{
		//2의 배수를 채워넣을 위치
		int pos = N-1;

		for (int j = N-1; j >=0; j--)
		{
			if (arr[i][j] != 0)
			{
				arr[i][pos--] = arr[i][j];
				
				if (pos + 1 == j)continue;

				arr[i][j] = 0;



			}
		}
	}



	for (int j = 0; j < N; j++) {
		for (int i = N - 1; i > 0; i--)
		{
			//b와 c가 같을때
			if (arr[j][i] == arr[j][i - 1]) {
				arr[j][i] = arr[j][i] + arr[j][i - 1];
				arr[j][i - 1] = 0;

				for (int k = i - 1; k >0;k--)
				{
					arr[j][k] = arr[j][k - 1];

				}
				arr[j][0] = 0;

			}
			else {
				//만약 c가 0이라면 
				if (arr[j][i] == 0) {
					arr[j][i] = arr[j][i - 1];
					arr[j][i - 1] = 0;
				}
				else {
					continue;
				}
			}
		}
	}
}

void 위로이동() {

	//숫자들을 모두 위쪽정렬을 한다.
	//2의 배수의 개수를 센다 그리고 그만큼 집어넣는다.
	for (int i = 0; i < N; i++)
	{
		//2의 배수를 채워넣을 위치
		int pos = 0;

		for (int j = 0; j < N; j++)
		{
			if (arr[j][i] != 0)
			{
				arr[pos++][i] = arr[j][i];
				
				if (pos - 1 == j)continue;

				arr[j][i] = 0;



			}
		}
	}





	for (int j = 0; j < N; j++) {
		for (int i = 0; i < N - 1; i++)
		{
			//a와 d가 같을때
			if (arr[i][j] == arr[i + 1][j])
			{
				arr[i][j] = arr[i][j] + arr[i + 1][j];
				arr[i + 1][j] = 0;

				for (int k = i + 1; k < N - 1;k++)
				{
					arr[k][j] = arr[k+1][j];

				}
				arr[N-1][j] = 0;




			}
			else {
				// a가 0이라면
				if (arr[i][j] == 0) {
					arr[i][j] = arr[i + 1][j];
					arr[i + 1][j] = 0;
				}
				else {
					continue;
				}
			}
		}
	}
}
void 아래이동() {

	//아래로 정렬을 한다.
	for (int i = 0; i < N; i++)
	{
		//2의 배수를 채워넣을 위치
		int pos = N - 1;

		for (int j = N - 1; j >= 0; j--)
		{
			if (arr[j][i] != 0)
			{
				arr[pos--][i] = arr[j][i];

				if (pos + 1 == j)continue;

				arr[j][i] = 0;



			}
		}
	}




	for (int j = 0; j < N; j++)
	{
		for (int i = N - 1; i > 0; i--)
		{
			if (arr[i][j] == arr[i - 1][j])
			{

				arr[i][j] = arr[i][j] + arr[i - 1][j];
				arr[i - 1][j] = 0;



				for (int k = i - 1; k > 0;k--)
				{
					arr[k][j] = arr[k-1][j];

				}
				arr[0][j] = 0;




			}
			else {
				if (arr[i][j] == 0)
				{
					arr[i][j] = arr[i - 1][j];
					arr[i - 1][j] = 0;
				}
				else {
					continue;
				}
			}
		}
		
	}
}
void game(int step) {
	if (step == 5) {
		for (int i = 0; i < N; i++)
		{
			for (int j = 0; j < N; j++)
			{
				big = max(big, arr[i][j]);
			}
		}
		return;
	}

	int copy_arr[20][20];
	//일단 4번 방향 바뀌기전 복사
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			copy_arr[i][j] = arr[i][j];
		}
	}
	//----------------------------

	왼쪽이동();
	game(step+1);
	//원상복구
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			arr[i][j] = copy_arr[i][j];
		}
	}

	오른쪽이동();
	game(step + 1);
	//원상복구
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			arr[i][j] = copy_arr[i][j];
		}
	}
	위로이동();
	game(step + 1);
	//원상복구
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			arr[i][j] = copy_arr[i][j];
		}
	}
	아래이동();
	game(step + 1);
	//원상복구
	for (int i = 0; i < 20; i++) {
		for (int j = 0; j < 20; j++) {
			arr[i][j] = copy_arr[i][j];
		}
	}



}
int main() {
	
	cin >> N;
	
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			cin >> arr[i][j];
		}
	}

	game(0);

	cout << big;
}

'Algorithm > BOJ' 카테고리의 다른 글

[백준 16236] 아기상어  (0) 2023.05.07
[백준 1475] 방번호  (0) 2023.05.03
[백준 14500] 테트로미노  (0) 2023.05.02
[백준 15683] 감시  (1) 2023.04.30
[백준 1005] ACM Craft  (0) 2023.04.29