BOARDCOVER (중하, p. 159)

ㄴ 모양의 Block들을 여러 방향으로 돌려보면 4가지 case가 나옴.
그걸로 모두 다 덮어보는 완탐을 구현하면 됨.
#include <bits/stdc++.h>
using namespace std;
struct Coord {
int x, y;
Coord() {}
Coord(int x, int y) : x(x), y(y) {}
};
struct Block {
Coord co[3];
Block(Coord co1, Coord co2, Coord co3) {
co[0] = co1;
co[1] = co2;
co[2] = co3;
}
};
Block blks[4] = {{{0, 0}, {1, 0}, {1, -1}},
{{0, 0}, {0, 1}, {1, 0}},
{{0, 0}, {0, 1}, {1, 1}},
{{0, 0}, {1, 0}, {1, 1}}};
string board[21];
int h, w, ans;
int empty_space_cnt;
bool CanPutBlockDown(int x, int y, const Block& blk) {
int cnt = 0;
for(int z = 0; z < 3; z++) {
int nx = x + blk.co[z].x;
int ny = y + blk.co[z].y;
if(nx < 0 || ny < 0 || nx >= h || ny >= w) return false;
if(board[nx][ny] == '.') cnt++;
}
return cnt == 3;
}
void PutBlockDown(int x, int y, const Block& blk) {
for(int z = 0; z < 3; z++) {
board[x + blk.co[z].x][y + blk.co[z].y] = '!';
}
}
void RemoveBlock(int x, int y, const Block& blk) {
for(int z = 0; z < 3; z++) {
board[x + blk.co[z].x][y + blk.co[z].y] = '.';
}
}
void Dfs(int x, int y, int cnt) {
if(cnt == empty_space_cnt) {
ans++;
return;
}
if(x == h - 1 && y == w || x == h) {
return;
}
if(y == w) {
Dfs(x + 1, 0, cnt);
return;
}
if(board[x][y] == '.') {
bool is_in = false;
for(int k = 0; k < 4; k++) {
if(CanPutBlockDown(x, y, blks[k])) {
is_in = true;
PutBlockDown(x, y, blks[k]);
Dfs(x, y + 1, cnt + 3);
RemoveBlock(x, y, blks[k]);
}
}
if(!is_in) return;
} else {
Dfs(x, y + 1, cnt);
}
}
void Init() {
empty_space_cnt = 0;
ans = 0;
}
int main() {
int tc;
cin >> tc;
while(tc--) {
Init();
cin >> h >> w;
for(int i = 0; i < h; i++) {
cin >> board[i];
}
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
if(board[i][j] == '.') empty_space_cnt++;
}
}
Dfs(0, 0, 0);
printf("%d\n", ans);
}
return 0;
}