백준 19235 모노미노도미노

Posted by : at

Category : Solution


Problem 문제풀이

 

내가 이렇게 실수가 많은 사람이라는 것을 알게 해준 문제이다.

1분을 빨리 풀려하다 1시간을 디버깅을 할 수 있다는 교훈을 주는 문제이다.

 


전략

  1. 초록색과 파란색 보드를 만든다.

  2. 주어진 좌표에서 블록을 떨어뜨린다.

  3. 한 행이 가득차게 되면 Clear하고 score을 1올린다.

  4. 만약 Clear했으면 Gravity를 주고 3. 을 실행한다.

  5. 더 Clear할 행이 없으면 Overflow를 검사한다.

  6. Overflow가 일어났으면 전체 행을 한 줄씩 밑으로 내리고 5. 를 반복한다.

  7. 모든 블록을 떨어뜨렸으면 score와 남은 블록의 수를 출력한다.


 

이 문제는 계획을 잘 세우는 사람만 풀 수 있다. 무턱대고 덤비는 습관은 버리는 것이 좋다. (경험담임)

곰곰히 생각해보면 초록색 보드와 파란색 보드를 굳이 따로 만들 필요가 없다는 것을 알 수 있다.

int board[2][6][4];						// color, row, col

 

 

이제 떨어뜨린 블록을 보드에 채우는 함수를 만들어보자.

t가 1일 때는 한 칸짜리 블록이고 2는 초록색 기준으로 1*2

3은 초록색 기준으로 2*1 블록이다. 파란색은 xy대칭을 시켜서 넣으면 된다.

 

void Game(int _t, int _x, int _y)
{
	if (_t == 1)
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 1; i < 6; i++)
		{
			if (board[0][i][_y] > 0)
			{
				board[0][i - 1][_y] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i][_y] = board_num;
			}
		}
		for (int i = 1; i < 6; i++)
		{
			if (board[1][i][_x] > 0)
			{
				board[1][i - 1][_x] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i][_x] = board_num;
			}
		}
	}
	else if (_t == 2)			// 초록색 기준 가로
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 1; i < 6; i++)
		{
			if (board[0][i][_y] > 0 || board[0][i][_y + 1] > 0)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i - 1][_y + 1] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i][_y] = board_num;
				board[0][i][_y + 1] = board_num;
			}
		}
		for (int i = 2; i < 6; i++)
		{
			if (board[1][i][_x] > 0)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i - 2][_x] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i][_x] = board_num;
			}
		}
	}
	else                  // 초록색 기준 세로
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 2; i < 6; i++)
		{
			if (board[0][i][_y] > 0)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i - 2][_y] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i][_y] = board_num;
			}
		}
		for (int i = 1; i < 6; i++)
		{
			if (board[1][i][_x] > 0 || board[1][i][_x + 1] > 0)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i - 1][_x + 1] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i][_x] = board_num;
				board[1][i][_x + 1] = board_num;
			}
		}
	}
	for (int c = 0; c < 2; c++)
	{
		Clear(c);
		Overflow(c);
	}
}

 

이렇게 넣는 작업까지는 5분이면 충분히 구현할 수 잇을 것이다. But! 오래 걸리더라도 실수 없이 하는 것이 제일 중요하다!

이제 Clear와 Overflow로 검사해보자. 먼저 Clear다.

 

void Clear(int color)
{
	bool ret = false;
	for (int i = 0; i < 6; i++)
	{
		ret = true;
		for (int j = 0; j < 4; j++)
		{
			if (board[color][i][j] == 0)
			{
				ret = false;
				break;
			}
		}
		if (ret)
		{
			for (int j = 0; j < 4; j++)
			{
				board[color][i][j] = 0;
			}
			score++;
			Gravity(color);
			Clear(color);
		}
	}
}

 

한 행이 꽉 차있으면 그 줄을 Clear하고 Gravity를 준다.

이 문제에서 제일 실수가 많이 나올 수 있는 Gravity를 살펴보자.

 

void Gravity(int color)
{
	bool ret = false;
	for (int i = 4; i >= 0; i--)
	{

		for (int j = 0; j < 4; j++)
		{
			if (board[color][i][j] > 0 && board[color][i + 1][j] == 0)
			{
				if (j > 0 && board[color][i][j] == board[color][i][j - 1])
				{
					if (board[color][i + 1][j - 1] == 0)
					{
						board[color][i + 1][j] = board[color][i][j];
						board[color][i + 1][j - 1] = board[color][i][j - 1];
						board[color][i][j] = 0;
						board[color][i][j - 1] = 0;
						ret = true;
					}
				}
				else if (j < 3 && board[color][i][j] == board[color][i][j + 1])
				{
					if (board[color][i + 1][j + 1] == 0)
					{
						board[color][i + 1][j] = board[color][i][j];
						board[color][i + 1][j + 1] = board[color][i][j + 1];
						board[color][i][j] = 0;
						board[color][i][j + 1] = 0;
						ret = true;
					}
				}
				else
				{
					board[color][i + 1][j] = board[color][i][j];
					board[color][i][j] = 0;
					ret = true;
				}
				if (ret)
				{
					Gravity(color);
				}
			}
		}
	}
}

 

내 좌우에 있는 블록과 내가 같은 번호의 블록이고 둘 중에 하나라도 땅에 붙어있으면 Gravity가 작용하지 않는다.

둘 다 공중에 있거나 내 옆에 같은 번호의 블록이 없을 경우 낙하시키고 Gravity를 다시 부른다.

모든 블록이 땅에 붙으면 Gravity는 종료된다. 마지막으로 Overflow 함수를 살펴보자.

 

void Overflow(int color)
{
	bool ret = false;
	for (int i = 0; i < 4; i++)
	{
		if (board[color][1][i] > 0)
		{
			ret = true;
			break;
		}
	}
	if (ret)
	{
		for (int i = 5; i > 0; i--)
		{
			for (int j = 0; j < 4; j++)
			{
				board[color][i][j] = board[color][i - 1][j];
			}
		}
		for (int i = 0; i < 4; i++)
		{
			board[color][0][i] = 0;
		}
		Overflow(color);
	}
}

 

주의!! board[color][0]행을 0으로 초기화시키지 않으면 무한루프에 빠질 수 있다.

이 문제 푸는데 2시간은 넘게 사용했다. 실수를 줄이는 습관을 키우고 싶다면 이 문제를 꼭 풀어보기 바란다.

전체 코드를 남기며 마무리하겠다. Good Luck!

 

#include <iostream>

using namespace std;

int N, t, x, y, board_num, score, cnt;

int board[2][6][4];						// color, row, col
void Game(int _t, int _x, int _y);
void Count();
void Clear(int color);
void Gravity(int color);
void Overflow(int color);

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cin >> N;
	for (int i = 1; i <= N; i++)
	{
		cin >> t >> x >> y;
		board_num = i;
		Game(t, x, y);

		/*cout << '\n';
		for (int j = 0; j < 6; j++)
		{
			for (int k = 0; k < 4; k++)
			{
				cout << board[0][j][k]<<' ';
			}
			cout << '\t';
			for (int k = 0; k < 4; k++)
			{
				cout << board[1][j][3-k] << ' ';
			}
		cout << '\n';
		}*/
	}
	Count();
	cout << score << '\n' << cnt;
	return 0;
}

void Game(int _t, int _x, int _y)
{
	if (_t == 1)
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 1; i < 6; i++)
		{
			if (board[0][i][_y] > 0)
			{
				board[0][i - 1][_y] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i][_y] = board_num;
			}
		}
		for (int i = 1; i < 6; i++)
		{
			if (board[1][i][_x] > 0)
			{
				board[1][i - 1][_x] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i][_x] = board_num;
			}
		}
	}
	else if (_t == 2)			// 초록색 기준 가로
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 1; i < 6; i++)
		{
			if (board[0][i][_y] > 0 || board[0][i][_y + 1] > 0)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i - 1][_y + 1] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i][_y] = board_num;
				board[0][i][_y + 1] = board_num;
			}
		}
		for (int i = 2; i < 6; i++)
		{
			if (board[1][i][_x] > 0)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i - 2][_x] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i][_x] = board_num;
			}
		}
	}
	else                  // 파란색 기준 가로
	{
		/* board[0] : 초록색
		   board[1] : 파란색	*/
		for (int i = 2; i < 6; i++)
		{
			if (board[0][i][_y] > 0)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i - 2][_y] = board_num;
				break;
			}
			if (i == 5)
			{
				board[0][i - 1][_y] = board_num;
				board[0][i][_y] = board_num;
			}
		}
		for (int i = 1; i < 6; i++)
		{
			if (board[1][i][_x] > 0 || board[1][i][_x + 1] > 0)
			{
				board[1][i - 1][_x] = board_num;
				board[1][i - 1][_x + 1] = board_num;
				break;
			}
			if (i == 5)
			{
				board[1][i][_x] = board_num;
				board[1][i][_x + 1] = board_num;
			}
		}
	}
	for (int c = 0; c < 2; c++)
	{
		Clear(c);
		Overflow(c);
	}
}

void Clear(int color)
{
	bool ret = false;
	for (int i = 0; i < 6; i++)
	{
		ret = true;
		for (int j = 0; j < 4; j++)
		{
			if (board[color][i][j] == 0)
			{
				ret = false;
				break;
			}
		}
		if (ret)
		{
			for (int j = 0; j < 4; j++)
			{
				board[color][i][j] = 0;
			}
			score++;
			Gravity(color);
			Clear(color);
		}
	}
}

void Gravity(int color)
{
	bool ret = false;
	for (int i = 4; i >= 0; i--)
	{

		for (int j = 0; j < 4; j++)
		{
			if (board[color][i][j] > 0 && board[color][i + 1][j] == 0)
			{
				if (j > 0 && board[color][i][j] == board[color][i][j - 1])
				{
					if (board[color][i + 1][j - 1] == 0)
					{
						board[color][i + 1][j] = board[color][i][j];
						board[color][i + 1][j - 1] = board[color][i][j - 1];
						board[color][i][j] = 0;
						board[color][i][j - 1] = 0;
						ret = true;
					}
				}
				else if (j < 3 && board[color][i][j] == board[color][i][j + 1])
				{
					if (board[color][i + 1][j + 1] == 0)
					{
						board[color][i + 1][j] = board[color][i][j];
						board[color][i + 1][j + 1] = board[color][i][j + 1];
						board[color][i][j] = 0;
						board[color][i][j + 1] = 0;
						ret = true;
					}
				}
				else
				{
					board[color][i + 1][j] = board[color][i][j];
					board[color][i][j] = 0;
					ret = true;
				}
				if (ret)
				{
					Gravity(color);
				}
			}
		}
	}
}

void Overflow(int color)
{
	bool ret = false;
	for (int i = 0; i < 4; i++)
	{
		if (board[color][1][i] > 0)
		{
			ret = true;
			break;
		}
	}
	if (ret)
	{
		for (int i = 5; i > 0; i--)
		{
			for (int j = 0; j < 4; j++)
			{
				board[color][i][j] = board[color][i - 1][j];
			}
		}
		for (int i = 0; i < 4; i++)
		{
			board[color][0][i] = 0;
		}
		Overflow(color);
	}
}

void Count()
{
	for (int i = 0; i < 6; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (board[0][i][j] > 0)
			{
				cnt++;
			}
			if (board[1][i][j] > 0)
			{
				cnt++;
			}
		}
	}
}

End


About GJ

안녕하세요 방문해주셔서 감사합니다. 혹시 보시면서 궁금하신것 있으시면 https://open.kakao.com/o/sivaz71c로 연락주세용~

Star
Useful Links