문제 : 게임판 덮기 (난이도 下)
위 문제를 '무식하게' 풀어보자.
문제 분석
L자 모형을 회전해서 나오는 모양들은 다음과 같다.
게임판 중 맨 좌측 상단 빈칸부터 재귀 호출을 시작한다.
A, B, C, D 네타입의 도형을 넣으면서 재귀를 수행하면 된다.
이 문제는 답이 항상 0인 사례가 존재한다.
1. 높이가 1인 경우
2. 빈칸 (흰색 칸)이 3의 배수가 아닌 경우
기저사례는 모든 칸을 다 채웠을 때이다.
구현
using namespace std;
//주어진 칸을 덮을 수 있는 네가지 방법.
//상대적인 위치 (dy, dx)
//별표시를 시작 위치로 잡았다.
const int cover_type[4][3][2] = {
{{0,0},{1,0},{1,1}}, //A
{{0,0},{0,1},{1,0}}, //B
{{0,0},{0,1},{1,1}}, //C
{{0,0},{1,0},{1,-1}}, //D
};
//delta 역할에 주목하자.
bool set(vector<vector<int>>& board, int y, int x, int type, int delta)
{
bool check = true;
for (int i = 0; i < 3; i++)
{
const int next_y = y + cover_type[type][i][0];
const int next_x = x + cover_type[type][i][1];
//벡터 사이즈 주의 H : board의 사이즈, L : board[i]의 사이즈.
if (next_y < 0 || next_y >= board.size() || next_x < 0 || next_x >= board[0].size())
check = false;
//set함수의 핵심.
//delta값을 더함으로써 초기화와 판단을 할 수 있다.
else if ((board[next_y][next_x] += delta) > 1)
check = false;
}
return check;
}
int fillBoard(vector<vector<int>> &board)
{
//채우지 않은 칸중 가장 좌상단칸을 찾는다.
int y = -1, x = -1;
for (int i = 0; i < board.size(); i++)
{
for (int j = 0; j < board[i].size(); j++)
{
if (board[i][j] == 0)
{
y = i;
x = j;
break;
}
}
//큰 for문 탈출문
if (y != -1) break;
}
//base case : 모든 칸을 채우면 1을 반환.
if (y == -1) return 1;
int ret = 0;
for (int type = 0; type < 4; type++)
{
if(set(board, y, x, type, 1))
ret += fillBoard(board);
//덮었던 블록 복구
set(board, y, x, type, -1);
}
return ret;
}
int main()
{
int C, H, W;
cin >> C;
while (C--)
{
cin >> H >> W;
vector<vector<int>> board(H, vector<int>(W,0));
int white_num = 0;
//# -> 1, . -> 0
for (int i = 0; i < H; i++)
{
for (int j = 0; j < W; j++)
{
char tmp;
cin >> tmp;
if (tmp == '#') board[i][j] = 1;
else
{
white_num++;
}
}
}
//항상 0인 사례
if (H == 1 || white_num % 3 != 0)
{
cout << white_num << "0" << '\n';
continue;
}
int cnt = fillBoard(board);
cout << cnt << '\n';
}
return 0;
}
회고
코드를 보면 핵심 부분은 책과 동일한 것을 볼 수 있다.
set함수에서 delta 의 역할이 신선하게 다가왔기에 그대로 사용했다.
아이디어는 간단?한 것 같지만 구현하는데 만만치 않다...
난도 下가 맞는지 싶다..
'알고리즘 > 알고리즘 문제 해결 전략' 카테고리의 다른 글
분할 정복 - 카라츠바 알고리즘 (1) | 2020.11.14 |
---|---|
분할 정복 (Divide & Conquer) (0) | 2020.11.13 |
무식하게 풀기(Brute force) - 4. 시계 맞추기 (0) | 2020.11.13 |
무식하게 풀기(Brute force) - 2. 소풍 (0) | 2020.11.08 |
무식하게 풀기(Brute force) - 1. 보글 게임 (3) | 2020.11.05 |