본문 바로가기
algorithm/ACMICPC

테트로미노 - 14500 (Solve 2)

by 에어컨조아 2019. 12. 14.

문제 : https://www.acmicpc.net/problem/14500

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다. 정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다. 아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누

www.acmicpc.net

기존에는 해당 도형들의 회전된 모든 경우의 수를 구하여서 배열에 적재 후 이를 탐색하여 해결을 하였다.

이 방법도 속도가 빠르고 괜찮은 방법이긴한데 하나라도 회전한 경우의 수를 못찾으면 문제를 틀리는 상황이 발생한다.

알아보니 DFS 방식으로도 풀길래 한번 시도를 해보았는데... 생각보다 오래걸렸다..

지금부터 왜 시간이 오래걸렸는지 하나씩 썰을 풀어보겠다.

일단 처음에는 DFS특성처럼 매개변수로 입력받은 하나의 도형을 기준으로 상하좌우를 탐색하여 경우의 수를 찾았다.

탈출조건 : Stack의 크기가 4이면 합의 크기를 비교한다음 크면 저장.

다음경우 :  입력받은 도형을 기준으로 상하좌우 탐색루프를 돌면서 범위에 충족되면 재귀호출.

이렇게 생각을 한다음 코드를 짰다.

실패코드 : 

더보기
#include <iostream>
#include <stack>
#include <limits>

using namespace std;
int num[501][501] = { 0 };
bool check[501][501] = { false };
int value = INT32_MIN;
int n, m;
int xMove[4] = { -1,1,0,0 };
int yMove[4] = { 0,0,-1,1 };
stack<std::pair<int, int>> temp;

//i, j를 기준으로 해당하는 모든 테트로미노
void solution(int i, int j, int count, int sum)
{
	//성공조건
	if (count == 4)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				cout << check[i][j];
			}
			cout << "\n";
		}

		cout << "\n";
		if (value < sum)
		{
			value = sum;
		}
		cout << sum << endl;
		return;
	}

	int c = 0;
	for (int k = 0; k < 4; k++)
	{
		//범위탐색
		int y = i + yMove[k];
		int x = j + xMove[k];
		if ((0 <= x && x < m) && (0 <= y && y < n))
		{
			if (check[y][x] == false)
			{
				temp.push(std::pair<int, int>(y, x));
				c++;
			}
		}
	}

	for (int k = 0; k < c; k++)
	{
		auto v = temp.top();
		temp.pop();
		check[v.first][v.second] = true;
		solution(v.first, v.second, count + 1, sum + num[v.first][v.second]);
		check[v.first][v.second] = false;
	}
}

int main()
{
	cin >> n >> m;

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> num[i][j];
		}
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			temp.push(std::pair<int, int>(i, j));
			check[i][j] = true;
			solution(i, j, 1, num[i][j]);
			check[i][j] = false;
		}
	}
	

	cout << value << endl;

	return 0;
}

하나씩 디버깅을 해보면서 틀린이유를 알아보니.. 

도형

위 도형의 모양이 절대 나올 수 없는 상황이였다...

왜 나올 수 없는 상황이였냐면 가정 자체부터 틀렸었다..

나는 가정을 DFS특성처럼 매개변수로 입력받은 하나의 도형을 기준으로 상하좌우를 탐색하여 경우의 수 라고 정의 하고 시작을 하였다.

하지만 위 방식대로 진행을 하면 절대 저 도형의 모양은 나올 수가 없다... 해서 방식을 달리해서 

Stack에 적재된 도형들을 기준으로 상하좌우 탐색을 하여 만들수 있는 모든 경우의 수 로 다시 정의했다.

탈출조건 : Stack의 크기가 4이면 합의 크기를 비교한다음 크면 저장.(위에서 정의한 것과 동일)

다음경우 :  Stack에 적재된 도형들을 기준으로 상하좌우 탐색루프를 돌면서 범위에 충족되면 재귀호출.

그래서 만들어진 코드는 아래와 같다. 

코드 : 

#include <iostream>
#include <stack>
#include <vector>
#include <limits>

using namespace std;

int N, M;
int num[500][500];
int mv[4][2] = { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } };
bool check[500][500] = { false };
vector<std::pair<int, int>> temp;
int value = INT32_MIN;

void solution(int n, int m, int sum)
{
	//해당 정점 방문
	temp.push_back(std::pair<int, int>(n, m));
	check[n][m] = true;

	//탈출조건
	if (temp.size() == 4)
	{
		/*for (int i = 0; i < N; i++)
		{
			for (int j = 0; j < M; j++)
			{
				cout << check[i][j];
			}
			cout << "\n";
		}*/

		if (value < sum)
		{
			value = sum;
		}
		return;
	}
	//다음경우
	int size = temp.size();
	for (int t = 0; t < size; t++) // 적재된 도형들을 기준
	{
		for (int i = 0; i < 4; i++)
		{
			int y = temp[t].first + mv[i][0];
			int x = temp[t].second + mv[i][1];
			if (check[y][x])
			{
				continue;
			}
			if ((0 <= y && y < N) && (0 <= x && x < M))
			{
				solution(y, x, sum + num[y][x]);
				temp.pop_back();
				check[y][x] = false;
			}
		}
	}
}
int main()
{
	cin >> N >> M;

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

	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
		{
			solution(i, j, num[i][j]);
			check[i][j] = false;
			temp.pop_back();
		}
	}
	cout << value << endl;
	return 0;
}

처음엔 Stack을 사용하여 적재를 하였지만 vector를 사용하도록 변경하였다... 

Stack은 만들어진 자료구조 특성상 모든경우 접근이 불가능 하며, 맨 마지막에 넣은 데이터만 접근이 가능하도록 되어있기 때문이다.  

'algorithm > ACMICPC' 카테고리의 다른 글

연구소 - 14502  (0) 2019.12.25
N-Queen - 9663  (0) 2019.12.23
사다리 조작 - 15684  (0) 2019.12.08
퇴사 - 14501  (0) 2019.12.03
부분수열의 합 - 1182  (0) 2019.12.03

댓글