코딩공작소
[백준]색종이 붙이기 본문
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.큰 종이부터 붙이면 되나보다 해서 큰종이 부터 붙였음.
2.반례가 있어서 작은종이로 오히려 더 작은 케이스를 만드는 경우가 있어서 5~1까지 종이의 사이즈를 바까주면서 붙임
3.반례 + 정례 를 해버리면 또 이상할거같아서 하나의 사이즈의 종이로 일률적으로 하는것은 아니라고 생각됨.
4.dfs를 통해 모든 조합을 통해 구해줘야할거 같음 ....ㅎ_ㅎ . 아래코드는 2번과정까지 ..
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
|
#include <iostream>
#include <cstring>
using namespace std;
/*
1.1x1~5x5 의 색종이를 5개씩 갖고 있다.
0~9 까지 가장 큰 색종이 부터 붙이면 될거같음.
5개가 넘어가면 안된다.
조합으로 해야되나보다.... 하나의 크기로만 쭈루룩 해서는 안되는것같다.
*/
int map1[10][10];
int map[10][10];
int paper[6] = { 0,5,5,5,5,5 }; //색종이의 개수.
int ans = 0;
bool Check(int len,int r,int c) {
bool flag = true;
for (int i = r; i < r + len; i++) {
for (int j = c; j < c + len; j++) {
if (map[i][j] != 1) { flag = false; j = c + len; i = r + len; }
}
}
return flag;
}
int main()
{
for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) cin >> map1[i][j];
int mm = 1e9; //최솟값을 구해야함.
for (int t = 5; t >= 1; t--) {
//초기화
memcpy(map, map1, sizeof(map));
for (int i = 1; i <= 5; i++) paper[i] = 5;
ans = 0;
for (int l = t; l >= 1; l--) {
//길이가 5인 색종이부터
for (int r = 0; r <= 10 - l; r++) {
for (int c = 0; c <= 10 - l; c++) {
if (Check(l, r, c) == true && paper[l] > 0) {
//붙일수 있다면
ans++; paper[l]--;
for (int i = r; i < r + l; i++) {
for (int j = c; j < c + l; j++) {
map[i][j] = l + 1;
}
}//붙이고 늘리기
}
}
}
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (map[i][j] == 1) {
ans = 1e9; i = 10; j = 10;
}
}
}
if (mm >= ans) mm = ans;
}
//Show();
if (mm == 1e9) { //값이 계속 바뀌지 않은경우 이렇게 처리하면 된다.
printf("-1\n"); return 0;
}
printf("%d\n", mm);
return 0;
}
|
cs |
완탐으로 마음을 비우고 다시 풀어봤다...
55%에서 계속 오답이 났었는데 조건하나를 추가해주니까 해결되었다... 1x1짜리를 붙일때가 문제였다.
맵의 크기가 10으로 고정되어있는데 범위검사를 안해주었다... 생각은 맵의 크기가 더 큰줄알고
뒤로가면 0을 만나서 자연스럽게 안붙이겠거니 생각했다.......
1.10으로 범위검사를 해주거나 2.맵을 그냥 16짜리 크기로 만드니까 통과했다...............
재귀는 재귀아래부분 부터의 논리적 흐름이 중요한거 같다... return 부분이 색다르고 어려웠다.
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
|
#include <iostream>
using namespace std;
int map[10][10];
int paper[6] = { 0,5,5,5,5,5 };
int ans = 1e9;
void dfs(int r, int cnt) {
if (ans != 1e9 && cnt >= ans) return; //이미 더큰것은 할 필요가 없음(가지치기)
for (int i = r; i < 10; i++) { //조합느낌으로 이미 붙인 행은 볼필요가 없다.(2차원 조합)
for (int j = 0; j < 10; j++) {
//전체를 돌면서 종이를 붙일수 있는지 확인
if (map[i][j] == 1) {
//1이 쓰여있으면
for (int l = 5; l >= 1; l--) {
//큰것부터 붙일수 있는지 확인
if (paper[l] <= 0 || l + i - 1 >= 10 || l + j - 1 >= 10) continue; //종이 없거나 범위 벗어나면 pass
bool flag = false;
for (int k = i; k < i + l; k++) {
for (int m = j; m < j + l; m++) {
if (map[k][m] == 0) { flag = true; k = i + l; m = j + l; }
}
}
if (flag == true) continue;// 못붙이면 다음으로 pass
//dfs
paper[l]--;
for (int k = i; k < i + l; k++) {
for (int m = j; m < j + l; m++) {
map[k][m] = 0;//붙이기
}
}
dfs(i, cnt + 1);
paper[l]++;
for (int k = i; k < i + l; k++) {
for (int m = j; m < j + l; m++) {
map[k][m] = 1;//떼기
}
}
}
//여기까지왔다는것은 1이 있지만 붙이지 못했다는 것(실패)
return;
}
if (i == 9 && j == 9) {
//모든 종이를 탐색했지만 실패 하지 않았다는 것
if (ans >= cnt) ans = cnt;
}
}
}
}
int main()
{
for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) cin >> map[i][j];
dfs(0, 0);
printf("%d\n", ans == 1e9 ? -1 : ans);
return 0;
}
|
cs |
'알고리즘 > 그리디&완탐' 카테고리의 다른 글
[백준]Z(분할정복)다시풀어보자 (0) | 2019.08.08 |
---|---|
[백준]체스판다시칠하기 (0) | 2019.08.06 |
[백준]스타트링크(두번째) (0) | 2019.08.02 |
[백준]감시 (0) | 2019.08.02 |
[백준]30_그리디?정수론? (0) | 2019.06.30 |