SWEA5656 벽돌깨기

2 분 소요

[SWEA 5656] 벽돌깨기

SW 벽돌깨기 문제 (로그인이 필요합니다)

시작 전

  • 유명한 문제라고 해서 풀어봤는데, 진짜 생소하고 어려웠다.
  • 처음에 구슬이 어디를 부숴야 최소 값이 나올지, 그리고 부숴진 벽돌에 대한 정렬을 어떻게 구현해야 할지, 그리고 벽돌이 부숴지는 연쇄작용에 대해 어떻게 풀어야 할지에 대해 감이 안왔다.(사실상, 다 몰랐던거다..)
  • 처음 구현할 때는 구슬이 처음 때리는 벽돌부터 시작해서 왼쪽, 오른쪽, 아래, 위 함수를 다 구현해서 거기서 또 재귀로 해봤다가 코드도 제대로 구현하지 못함..

코드 리뷰

  • 최소값은 맵크기와 구슬 던지는 횟수가 작아서 완전탐색을 재귀를 통해 구슬 던지는 횟수 N번이 다 쓰여질때마다 최소값을 저장해두는 방식으로 했다.
  • 연쇄작용은 4방향을 다 보되, * K를 써서 해결했다(코드에 있음)
  • 정렬 부분은 쉽다.
  • 정답률에 비해 생소해서 그런지 너무 어렵게 느껴졌다.
#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 0xFFFFFF;
using namespace std;

int N, W, H;
int board[20][20];
int dc[4] = { 0,0,1,-1 };
int dr[4] = { 1,-1,0,0 };
int Min = INF;

void recur(int);
void stonesort();
void stonebreak(int, int);

void recur(int checkp) { //구슬을 던진 횟수에 대해 재귀적으로 접근
	int copy[20][20] = {};
	if (checkp == 0) { //N번만큼 구슬 던진 경우
		int cnt = 0;
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				if (board[i][j] != 0) cnt++;
			}
		}
		Min = min(Min, cnt);
		return;
	}
	for (int i = 0; i < W; i++) { //N번만큼 아직 안 던진 경우
		int x = 0;
		while (x < H&&board[x][i] == 0) x++;
		for (int h = 0; h < H; h++) { // 재귀 돌리기 전으로 돌아가기위해 보드판 복사해놓기!
			for (int w = 0; w < W; w++) {
				copy[h][w] = board[h][w];
			}
		}
		stonebreak(x, i); //구슬 하나 써서 벽돌 깨러가는 함수
		stonesort(); // 부숴진 부분 정렬
		recur(checkp - 1); // 구슬 하나써서 재귀로 들어가기
		for (int h = 0; h < H; h++) { //보드판 복사해놓은것 가져온다.
			for (int w = 0; w < W; w++) {
				board[h][w] = copy[h][w];
			}
		}
	}
}

void stonebreak(int x, int y) {
	int score = board[x][y];
	board[x][y] = 0;
	for (int k = 0; k < score; k++) {
		for (int n = 0; n < 4; n++) {
			int xnext = x + dc[n] * k; //네방향을 보되, 그 벽돌에 들어간 점수만큼 보기위해
			int ynext = y + dr[n] * k;
			if (xnext < H&&xnext >= 0 && ynext >= 0 && ynext < W&&board[xnext][ynext] != 0) stonebreak(xnext, ynext);
		}
	}
}

void stonesort() { //벽돌 재정렬
	for (int i = 0; i < W; i++) {
		for (int j = H - 1; j > 0; j--) {
			if (board[j][i] == 0) {
				for (int k = j - 1; k >= 0; k--) {
					if (board[k][i] != 0) {
						board[j][i] = board[k][i];
						board[k][i] = 0;
						break;
					}
				}
			}
		}
	}
}
int main() {
	int T;
	scanf("%d", &T);
	for (int t = 1; t <= T; t++) {
		scanf("%d%d%d", &N, &W, &H);
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				scanf("%d", &board[i][j]);
			}
		}
		recur(N);
		printf("#%d %d\n", t, Min);
		memset(board, 0, sizeof(board));
		Min = INF;
	}
	return 0;
}

댓글남기기