본문 바로가기

브루트 포스/브루트포스(재귀)

색종이 붙이기

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

 

17136번: 색종이 붙이기

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

www.acmicpc.net

5, 4, 3, 2, 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
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
 
using namespace std;
 
int ans = 100;
int map[14][14];
 
 
int paper[5= { 55555 };
 
 
void fill(int row, int col, int k, int v)
{
    for (int i = row; i <= row + k; i++)
    {
        for (int j = col; j <= col + k; j++)
        {
            map[i][j] = v;
        }
    }
}
 
bool bound(int row, int col, int k)
{
    if (row + k >= 10 || col + k >= 10)
        return false;
    else
        return true;
}
 
bool check(int row, int col, int k)
{
    for (int i = row; i <= row + k; i++)
    {
        for (int j = col; j <= col + k; j++)
        {
            if (map[i][j] == 0)
                return false;
        }
    }
    return true;
}
 
bool full_check()
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            if (map[i][j] == 1)
                return false;
        }
    }
    return true;
}
 
void go(int cnt)
{
 
    if (ans < cnt)
    {
        return;
    }
 
    if (full_check())
    {
        if (ans > cnt)
            ans = cnt;
        return;
    }
 
 
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            if (map[i][j] == 1)
            {
                for (int k = 4; k >= 0; k--)
                {
                    if (bound(i, j, k) && paper[k] > 0 && check(i, j, k))
                    {
                        paper[k]--;
                        fill(i, j, k, 0);
                        go(cnt + 1);
 
                        paper[k]++;
                        fill(i, j, k, 1);
                    }
                }
                // 맨 처음 1부터 재귀를 쭉 돌리면 더 이상 할 필요가 없다!
                  // 그러므로 return;
                return;
            }
        }
    }
}
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
 
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
            cin >> map[i][j];
    }
    
    go(0);
    
    if (ans == 100)
        cout << -1 << '\n';
    else
        cout << ans << '\n';
    
    return 0;
}
cs

 

 paper[k]--;

fill(i, j, k, 0);
go(cnt + 1);
 
paper[k]++;
fill(i, j, k, 1);
 
치킨 배달부터 해서 신기한 소수
엄청 풀었던 브루트포스 재귀이다.
선택 / not 선택
 
 
 if (ans < cnt)
{
   return;
}
 
이건 안넣으면 정답은 되는데 시간이 20ms 차이난다.
ans 보다 크다면 굳이 필요가 없으므로
return; 해서 시간을 단축시키자
 

'브루트 포스 > 브루트포스(재귀)' 카테고리의 다른 글

주사위 윷놀이  (1) 2023.10.10
청소년 상어  (1) 2023.10.06
게리맨더링  (0) 2023.09.18
ABCDE  (0) 2023.07.19
모든 순열(재귀 ver)  (0) 2023.05.30