0. 개요

https://www.acmicpc.net/problem/17136
2019년 4월 6일
남은 색종이를 세면서 1이 있는 위치마다 덮을 색종이를 선택한다.

1. 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cstring>
#include <cstdlib>

using namespace std;

void printBoard();
void printVisit();

#define MAX_N 12

int N, M;
int board[MAX_N][MAX_N];
bool isVisited[MAX_N][MAX_N];
vector<pair<int, int> > vec;

int dx[3] = { 0, 1, 1 };
int dy[3] = { 1, 0, 1 };

int paper[6];
int res;

int getMaxSize(int r, int c)
{
	for (int nSize = 5; nSize > 0; nSize--)
	{
		bool isFail = false;
		for (int i = r; i < r + nSize; i++)
		{
			if (i >= N)
			{
				isFail = true;
				break;
			}
			for (int j = c; j < c + nSize; j++)
			{
				if \(j >= N \|| board\[i]\[j] == 0 \|| isVisited\[i]\[j])
				{
					isFail = true;
					break;
				}
			}
			if (isFail)
				break;
		}
		if (isFail)
			continue;
		else
			return nSize;
	}
	return 1;
}
void cover(int size, int sr, int sc)
{
	for (int i = sr; i < sr + size; i++)
		for (int j = sc; j < sc + size; j++)
			isVisited[i][j] = 1;
}

void uncover(int size, int r, int c)
{
	for (int i = r; i < r + size; i++)
		for (int j = c; j < c + size; j++)
			isVisited[i][j] = 0;
}
bool isFin()
{
	for (int i = 0; i < vec.size(); i++)
	{
		int r = vec[i].first;
		int c = vec[i].second;

		if (!isVisited[r][c])
			return false;
	}
	return true;
}

int dfs(int idx, int cnt)
{
	if (idx >= vec.size() && isFin())
	{
		res = min(res, cnt);
		return 0;
	}
	if (cnt >= res)
		return 0;

	int r = vec[idx].first;
	int c = vec[idx].second;
	
	// 통과
	if (isVisited[r][c])
		dfs(idx + 1, cnt);
	else
	{
		int size = getMaxSize(r, c);
		for (int k = size; k >= 1; k--)
		{
			if (paper[k] > 0)
			{
				paper[k]--;
				cover(k, r, c);
				dfs(idx + 1, cnt + 1);
				uncover(k, r, c);
				paper[k]++;
			}
		}
	}
}

int main()
{
//	freopen("in.txt", "r", stdin);

	int testcase = 1;
//	scanf("%d", &testcase);
	for (int tc = 1; tc <= testcase; tc++)
	{
		memset(isVisited, 0, sizeof(isVisited));
		N = 10;
		res = 1e9;
		for (int i = 1; i <= 5; i++)
			paper[i] = 5;

		for (int i = 0; i < N; i++)
		{
			for (int j = 0; j < N; j++)
			{
				scanf("%d", &board[i][j]);
				if (board[i][j] == 1)
					vec.push_back({ i, j });
			}
		}
		dfs(0, 0);
		printf("%d\n", res >= 1e9 ? -1 : res);
	}
}

2. 풀이

  1. 덮을 위치들을 vector로 저장
  2. 방문 여부를 배열로 저장
  3. 방문 여부를 확인해 이미 덮힌 곳은 통과하면서 덮을 색종이를 선택
  4. 덮을 수 있는 최대 크기를 구하면 그 밑의 크기는 다 덮을 수 있다는 말이 됨.