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을 만나면 거기서부터 붙일 수 있는 가장 큰 색종이를 붙이면 된다고 생각했습니다.
하지만 다음 예제를 생각해보면
- 좌표 (1, 1) 에서 길이 5짜리 색종이를 붙입니다. (사용한 총 색종이 : 1장)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- (1, 6) 좌표에서 길이 3짜리 색종이를 붙입니다. (사용한 총 색종이 : 2장)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- (4, 6) 좌표에서 길이 3짜리 색종이를 붙입니다. (사용한 총 색종이 : 3장)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- (5, 1) 좌표에서 길이 2짜리 색종이 2 장을 붙입니다. (사용한 총 색종이 : 5장)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- (6, 5) 좌표에서 길이 1짜리 색종이 5장을 붙입니다. (사용한 총 색종이 : 10장)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
이렇게 하면 사용한 색종이가 총 10 장이 되는데, 정답은 길이 4짜리 색종이를 4개 붙이면 됩니다. 그렇기 때문에 좌표에서 1을 만나게 되면 길이 5짜리 부터 붙일 수 있는지 확인하고, 붙일 수 없다면 길이 4, 3, 2, 1 순으로 확인하여 붙이고 다음으로 넘어가는 재귀적인 방법으로 모든 길이의 색종이를 붙여봤을 때 최소값을 구하는 방법으로 접근해야 합니다.
[ 문제 풀이 ]
1. 길이 1부터 5까지 색종이를 나타내는 paper 배열에 1 번째 인덱스부터 5 번째 인덱스까지 5를 저장해줍니다.
2. 이제 DFS(x 좌표, y 좌표, 사용한 색종이의 개수) 를 시작하는데 (0, 0) 좌표부터 진행합니다.
(1) 재귀를 빠져나가는 기저조건은 좌표가 (10, 10) 까지 갔을 때와 사용한 색종이 개수 cnt 를 최소로 하는 것이 정답이기 때문에 cnt 가 최솟값 answer 보다 커지게 되면 재귀를 종료합니다.
(2) 2차원 배열에서 1을 만나면 색종이를 붙여보는데 길이 5 짜리 부터 1 짜리 까지 붙입니다. 여기서 주의해야 할점은 papering(x 좌표, y좌표, 사용할 색종이의 길이, 2차원 배열에 표시할 변수) 로 색종이를 붙여주고 사용한 길이의 색종이를 -1 해주는데, 색종이를 붙이면 그 자리의 좌표를 0으로 하고 붙이고 나서는 그 자리를 다시 1로 붙여놔야 다음 길이의 색종이를 한번 더 붙여볼 수 있습니다. 그래서 papering(r, c, i, 0) (길이 i 짜리 색종이 붙이기) -> paper[i] -- (길이 i짜리 색종이 -1) -> DFS -> papering(r, c, i, 1) (길이 i짜리 붙인 색종이 떼기) -> paper[i] ++ (사용한 색종이 복귀) 순서로 해줘야 합니다.
3. 이렇게 재귀적으로 완전탐색하면서 좌표가 (10, 10) 이 됐을 때 answer 에 사용한 색종이 cnt 의 최솟값을 비교해주면서 저장하면 정답입니다.
import java.util.Scanner;
public class Main {
static int[][] map = new int[10][10];
static int[] paper = {0,5,5,5,5,5};
static int answer = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for(int i=0; i<10; i++) {
for(int j=0; j<10; j++) {
map[i][j] = sc.nextInt();
}
}
DFS(0, 0, 0);
System.out.println(answer == Integer.MAX_VALUE ? -1 : answer);
}
public static void DFS(int r, int c, int cnt) {
if(r >= 9 && c > 9) {
answer = Math.min(answer, cnt);
return;
}
if(answer <= cnt) return;
if(c > 9) {
DFS(r+1, 0, cnt);
return;
}
if(map[r][c] == 1) {
for(int i=5; i>=1; i--) {
if(paper[i] > 0 && check(r, c, i)) {
papering(r, c, i, 0);
paper[i]--;
DFS(r, c+1, cnt+1);
papering(r, c, i, 1);
paper[i]++;
}
}
} else DFS(r, c+1, cnt);
}
public static void papering(int x, int y, int size, int state) {
for(int i=x; i<x+size; i++) {
for(int j=y; j<y+size; j++) {
map[i][j] = state;
}
}
}
public static boolean check(int x, int y, int size) {
for(int i=x; i<x+size; i++) {
for(int j=y; j<y+size; j++) {
if(!isInside(i, j) || map[i][j] != 1) return false;
}
}
return true;
}
public static boolean isInside(int x, int y) {
return x>=0 && x<10 && y>=0 && y<10;
}
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
[SWEA] 1861. 정사각형 방 (0) | 2020.02.10 |
---|---|
[백준] 4179. 불! (0) | 2020.02.05 |
[정올] 1169. 주사위 던지기1 (0) | 2020.02.01 |
[백준] 11559. Puyo Puyo (0) | 2020.02.01 |
[SWEA] 2007. 패턴 마디의 길이 (0) | 2020.01.29 |