알고리즘

[BOJ / 비트마스크 DFS] 17136 색종이 붙이기

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

 

17136 색종이 붙이기

 

알고리즘 : 비트마스크 DFS

삼성 A형 기출문제입니다. 문제 풀이 방법은 1767 프로세서 연결하기와 매우 유사합니다.

https://mumomu.tistory.com/13?category=863413

 

[SWEA / 삼성A형기출] 1767 프로세서 연결하기 풀이

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV4suNtaXFEDFAUf SW Expert Academy SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요! swexpertacademy..

mumomu.tistory.com

이 문제의 특징을 보면 맵이 한 줄이 10으로 고정되어 있고 0과 1로 이루어진 것을 알 수 있습니다.

이는 하나의 int형으로 한 줄을 관리할 수 있다는 것이고 위의 문제와 유사합니다.

이를 이용하면 시간을 많이 단축할 수 있습니다.

 

그렇게 가능한 칸마다 남아있는 5*5~1*1의 색종이를 붙이고 다음 칸으로 진행하는 것을 반복하면

최저 횟수가 나옵니다. 

 

예전 초등학교 정보올림피아드 지역예선에서 비슷한 문제를 봤던 것 같습니다.

 

 

 

 

< CODE >


#include <iostream>
#include <vector>

using namespace std;

#define MAX 10

vector<pair<int, int>> v;
int result = 987654321;

// 색종이를 붙일 수 있는지 확인
bool bitCheck(int bit, int x, int width)
{
	int chk = (((1 << width) - 1) << x);

	return chk == (chk & bit);
}

// 해당영역의 1을 0으로 바꿔야하므로 해당부분을 1로 만든 뒤 반전하여 &연산
void bitChange(int & bit, int x, int width)
{
	bit &= ~(((1 << width) - 1) << x);
}

void dfs(int cnt, int bit[MAX], int remain[6], int amount)
{
	if (amount == v.size())
	{
		int total = 0;

		for (int i = 1; i < 6; i++)
			total += (5 - remain[i]);

		if (total < result)
			result = total;

		return;
	}
	else if (cnt == v.size())
		return;

	int y = v[cnt].first;
	int x = v[cnt].second;

	if (!bitCheck(bit[y], x, 1))
		dfs(cnt + 1, bit, remain, amount);

	int base[MAX];

    // 비트 복구를 위한 베이스
	for (int i = 0; i < MAX; i++)
		base[i] = bit[i];

	for (int i = 5; i > 0; i--)
	{
		if (remain[i] == 0)
			continue;

		bool chk = true;

		for (int j = 0; j < i; j++)
			chk &= bitCheck(bit[y + j], x, i);

		if (chk)
		{
			for (int j = 0; j < i; j++)
				bitChange(bit[y + j], x, i);

			remain[i] -= 1;

			dfs(cnt + 1, bit, remain, amount + i * i);

			remain[i] += 1;

			for (int j = 0; j < i; j++)
				bit[y + j] = base[y + j];
		}
	}
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	int bit[MAX] = { 0, };
	int remain[6] = { 0,5,5,5,5,5 };
	int amount = 0;

	for (int i = 0; i < MAX; i++)
	{
		for (int j = 0; j < MAX; j++)
		{
			int num;

			cin >> num;

			if (num == 1)
			{
				bit[i] |= (1 << j);
				v.push_back({ i,j });
			}
		}
	}

	dfs(0, bit, remain, 0);

	if (result == 987654321)
		cout << "-1\n";
	else
		cout << result << '\n';

	return 0;
}

56ms로 통과하였습니다.

 

 

#삼성A형기출 #백준 17136 #17136 색종이붙이기풀이