본문 바로가기
ps

[백준] 17136 - 색종이 붙이기

by kariskan 2022. 7. 27.

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

 

17136번: 색종이 붙이기

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

www.acmicpc.net

 

이 문제는 10 * 10 크기의 종이가 고정되어 있다는 걸로 보아 완전 탐색(+ 백트래킹)의 느낌이 났다.

 

처음에는 만약 1을 발견한다면 항상 가능한 큰 종이부터 붙이게끔 그리디 하게 풀었다.

하지만, 만약 8 * 8 크기의 1을 그리디 하게 붙이면 5 * 5 1장, 3 * 3 2장, 2 * 2 2장, 1 * 1 5장 총 10장을 사용하지만,

최선의 방법은 4 * 4를 4장 붙이는 것이다.

따라서 모든 경우의 수를 다 해보아야 한다.

 

  1. x좌표를 1부터 10까지, y좌표를 1부터 10까지 모두 탐색하며 1을 찾는다.
  2. 색종이를 붙일 수 있는지 판단한 후,
  3. 붙일 수 있다면 붙이고 색종이의 수를 갱신시켜준 후 다음 탐색을 한다.

이때 어떤 순서로 색종이를 붙어야 하는지 확실하지 않으므로 백트래킹 기법을 이용해 모든 경우의 수를 다 써본다.

 

#include <iostream>
using namespace std;

int map[10][10], p[6] = { 0,5,5,5,5,5 };
int ans = -1;

void go(int x, int y, int cnt) {
	if (ans != -1 && ans < cnt) return;

	if (x == 10) {
		if (ans == -1 || ans > cnt) {
			ans = cnt;
		}
		return;
	}
	
	if (y == 10) {
		go(x + 1, 0, cnt);
		return;
	}

	if (map[x][y] == 0) {
		go(x, y + 1, cnt);
		return;
	}

	for (int s = 1; s <= 5; s++) {
		if (x + s > 10 || y + s > 10 || p[s] == 0)continue;

		bool ok = true;
		for (int i = x; i < x + s; i++) {
			for (int j = y; j < y + s; j++) {
				if (map[i][j] != 1) {
					ok = false;
					break;
				}
			}
			if (!ok)break;
		}
		if (!ok)continue;

		for (int i = x; i < x + s; i++) {
			for (int j = y; j < y + s; j++) {
				map[i][j] = 0;
			}
		}
		p[s]--;
		go(x, y + s, cnt + 1);
		p[s]++;
		for (int i = x; i < x + s; i++) {
			for (int j = y; j < y + s; j++) {
				map[i][j] = 1;
			}
		}
	}
}

int main() {
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			cin >> map[i][j];
		}
	}
	
	go(0, 0, 0);

	cout << ans;
}

 

'ps' 카테고리의 다른 글

[백준] 1562 - 계단수  (0) 2022.08.03
[백준] 2610 - 회의준비  (0) 2022.08.01
[백준] 2533 - 사회망 서비스(SNS)  (0) 2022.07.27
[백준] 9328 - 열쇠  (0) 2022.07.27
[백준] 1941 - 소문난 칠공주  (0) 2022.07.27

댓글