본문 바로가기

알고리즘/백준 문제풀기

BOJ 백준 17136 색종이 붙이기

 

#include <stdio.h>
#include <vector>
#include <memory.h>

using namespace std;

const int SIZE = 10;
int arrMap[SIZE][SIZE];
bool arrBoolMap[SIZE][SIZE];
int arrCount[5];

struct EmptySpace { int x, y; };
vector<EmptySpace>	vecEmptySpaces;

int		g_nCnt = 999999999;
int		g_nRemainArea = 0;
bool	g_bFind = false;

void Input()
{
	for (int i = 0; i < SIZE; ++i)
	{
		for (int j = 0; j < SIZE; ++j)
		{
			scanf("%d", &arrMap[i][j]);
			if (arrMap[i][j])
			{
				g_nRemainArea++;
				vecEmptySpaces.push_back({ i, j });
			}
		}
	}

	for (int i = 0; i < 5; ++i)
		arrCount[i] = 5;
}

bool CheckArea(int x, int y, int n)
{
	int xLimit = x + n;
	int yLimit = y + n;
	if (xLimit > SIZE || yLimit > SIZE)
		return false;

	for (int i = x; i < xLimit; ++i)
	{
		for (int j = y; j < yLimit; ++j)
		{
			if (arrBoolMap[i][j] || !arrMap[i][j])
				return false;
		}
	}
	return true;
}

int ChangeBoolMap(int x, int y, int n, bool b)
{
	int xLimit = x + n;
	int yLimit = y + n;
	int nCnt = 0;

	for (int i = x; i < xLimit; ++i)
	{
		for (int j = y; j < yLimit; j++)
		{
			arrBoolMap[i][j] = b;
			if (arrMap[i][j])
				nCnt++;
		}
	}
	return nCnt;
}

// 시작점, 사용한 종이 개수, 비어있는 공간의 수
void solution(int nIdx, int nCnt, int nRemain)
{
	if (nRemain == 0)
	{
		g_bFind = true;
		if (g_nCnt > nCnt)
			g_nCnt = nCnt;
		return;
	}

	if (nCnt >= g_nCnt)
		return;

	int cur_x = vecEmptySpaces[nIdx].x;
	int cur_y = vecEmptySpaces[nIdx].y;

	// 종이가 붙여져 있는 곳인 경우
	if (arrBoolMap[cur_x][cur_y])
		solution(nIdx + 1, nCnt, nRemain);

	for (int j = 0; j <= 4; ++j)
	{
		if (arrCount[j] && CheckArea(cur_x, cur_y, j + 1))
		{
			arrCount[j]--;
			int nRemove = ChangeBoolMap(cur_x, cur_y, j + 1, true);

			solution(nIdx + 1, nCnt + 1, nRemain - nRemove);

			ChangeBoolMap(cur_x, cur_y, j + 1, false);
			arrCount[j]++;
		}
	}
}

void PrintResult()
{
	if (g_bFind)
	{
		printf("%d\n", g_nCnt);
	}
	else
	{
		printf("-1\n");
	}
}

int main()
{
	Input();
	solution(0, 0, g_nRemainArea);
	PrintResult();
	return 0;
}

https://www.acmicpc.net/problem/17136

 

17136번: 색종이 붙이기

<그림 1>과 같이 정사각형 모양을 한 다섯 종류의 색종이가 있다. 색종이의 크기는 1×1, 2×2, 3×3, 4×4, 5×5로 총 다섯 종류가 있으며, 각 종류의 색종이는 5개씩 가지고 있다. <그림 1> 색종이를 크기가 10×10인 종이 위에 붙이려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 0 또는 1이 적혀 있다. 1이 적힌 칸은 모두 색종이로 덮여져야 한다. 색종이를 붙일 때는 종이의 경계 밖으로 나가서는 안되고, 겹쳐

www.acmicpc.net

문제 풀이)

    1. 입력을 받으면서 색종이를 붙여야 할 점의 좌표를 벡터에 push해주고,

       색종이를 붙여야 할 점(1)의 총 개수를 저장한다.

 

    int nIdx : 색종이를 붙여야할 점들이 저장되어 있는 벡터의 index

    int nCnt = 현재까지 사용한 종이의 개수

    int nRemain : 남아 있는 색종이를 붙여야 할 점의 개수

 

    2. 재귀 방식으로, 인자로는 ( nIdx, nCnt, nRemain ) 이렇게 총 3가지이다.

 

    3. 만약 nRemain이 0이라면, 모든 공간에 색종이를 붙인 것이므로 방법을 찾았음을 표시하고

       최소 색종이의 수를 저장하는 변수와 비교하여 더 적을 경우 갱신해준다.

       nRemain이 0이 아니라면 색종이를 더 붙여야 하므로 4번으로 넘어간다.

 

    4. 색종이를 붙이기 전에, 해당 점이 이미 색종이로 덮여있는 지 확인하고, 덮여져 있다면 다음 점으로 넘어간다(3번)

       만약 덮여있지 않다면, 5번으로 넘어간다.

 

    5. 해당 점에 대해 5가지의 색종이를 모두 붙여보는 완전탐색을 이용한다.

 

 

 

'알고리즘 > 백준 문제풀기' 카테고리의 다른 글

BOJ 백준 1793 타일링  (1) 2019.05.16
BOJ 백준 11727 2xN 타일링 2  (0) 2019.05.16
BOJ 백준 11726 2xN 타일링  (0) 2019.05.16
BOJ 백준 2573 빙산  (0) 2019.05.11
BOJ 백준 3055 탈출  (0) 2019.05.10