알고리즘/BOJ

[BOJ] 17136. 색종이 붙이기

재담 2022. 2. 15. 00:42

문제 원본 : https://www.acmicpc.net/problem/17136

 

17136번: 색종이 붙이기

<그림 1>과 같이 정사각형 모양을 한 다섯 종류의 색종이가 있다. 색종이의 크기는 1×1, 2×2, 3×3, 4×4, 5×5로 총 다섯 종류가 있으며, 각 종류의 색종이는 5개씩 가지고 있다. <그림 1> 색종이를 크

www.acmicpc.net

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

int map[10][10];
vector<pair<int, int>> v;
int blk_cnt[5] = { 5,5,5,5,5 };
int cnt;
int ans;
bool succ;

bool possible(int r, int c, int n)
{
	if (r + n > 10 || c + n > 10) return false;

	for (int i = r; i < r + n; i++)
		for (int j = c; j < c + n; j++)
			if (map[i][j] != 1)
				return false;
	return true;
}

bool clear()
{
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			if (map[i][j] == 1)
				return false;
	return true;
}

void useBlock(int r, int c, int n)
{
	for (int i = r; i < r + n; i++)
		for (int j = c; j < c + n; j++)
			map[i][j] = n + 1;
}

void go(int r, int c)
{
	int back_map[10][10];
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			back_map[i][j] = map[i][j];

	int size = v.size();
	for (int i = 5; i >= 1; i--)
	{
		if (possible(r, c, i) && blk_cnt[i - 1])
		{
			blk_cnt[i - 1]--;
			cnt++;
			if (cnt > ans)
			{
				cnt--;
				blk_cnt[i - 1]++;
				return;
			}
			useBlock(r, c, i);

			if (clear())
			{
				ans = min(cnt, ans);
				succ = true;
			}
			for (int i = 0; i < size; i++)
			{
				if (map[v[i].first][v[i].second] == 1)
				{
					go(v[i].first, v[i].second);
					break;
				}
			}
			cnt--;
			blk_cnt[i - 1]++;
			for (int i = 0; i < 10; i++)
				for (int j = 0; j < 10; j++)
					map[i][j] = back_map[i][j];
		}
	}
}


int main()
{
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
		{
			cin >> map[i][j];
			if (map[i][j])
				v.push_back(make_pair(i, j));
		}

	ans = 1234567890;

	if (v.size() == 0)
	{
		printf("0\n");
		return 0;
	}
	go(v[0].first, v[0].second);
	succ ? printf("%d\n", ans) : printf("-1\n");
}
  • 큰 종이부터 붙여가면서 안 되는 경우를 가지치기하는 방식으로 해결.
  • 백트래킹은 아직도 어렵다.