H*W 크기의 게임판이 있습니다. 게임판은 검은 칸과 흰 칸으로 구성된 격자 모양을 하고 있는데 이 중 모든 흰 칸을 3칸짜리 L자 모양의 블록으로 덮고 싶습니다. 이 때 블록들은 자유롭게 회전해서 놓을 수 있지만, 서로 겹치거나, 검은 칸을 덮거나, 게임판 밖으로 나가서는 안 됩니다. 위 그림은 한 게임판과 이를 덮는 방법을 보여줍니다.
게임판이 주어질 때 이를 덮는 방법의 수를 계산하는 프로그램을 작성하세요.
력의 첫 줄에는 테스트 케이스의 수 C (C <= 30) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 2개의 정수 H, W (1 <= H,W <= 20) 가 주어집니다. 다음 H 줄에 각 W 글자로 게임판의 모양이 주어집니다. # 은 검은 칸, . 는 흰 칸을 나타냅니다. 입력에 주어지는 게임판에 있는 흰 칸의 수는 50 을 넘지 않습니다.
출력
한 줄에 하나씩 흰 칸을 모두 덮는 방법의 수를 출력합니다.
3
3 7
#.....#
#.....#
##...##
3 7
#.....#
#.....#
##..###
8 10
##########
#........#
#........#
#........#
#........#
#........#
#........#
##########
0
2
1514
const L_POSITIONS = [
[
[0, 0],
[1, 0],
[1, -1],
],
[
[0, 0],
[0, 1],
[1, 0],
],
[
[0, 0],
[1, 0],
[1, 1],
],
[
[0, 0],
[0, 1],
[1, 1],
],
];
const fs = require("fs");
const data = fs.readFileSync("./test.txt", "utf8");
const input = data.split("\r\n");
let c = input[0];
let curTc = 1;
let h, w, board, numOfComma;
while (c--) {
[h, w] = input[curTc].split(" ").map(Number);
board = input.slice(curTc + 1, curTc + 1 + h);
curTc += h + 1;
board = board.map((v) => v.split(""));
numOfComma = getNumOfComma(w, h, board);
if (numOfComma % 3 !== 0) {
console.log(0);
continue;
}
console.log(recursion(board, 0));
}
function recursion(board, numOfL) {
if (numOfL === numOfComma / 3) return 1;
const [curI, curJ] = getCommaXY(board);
let ret = 0;
for (let i = 0; i < 4; i++) {
const l1 = L_POSITIONS[i][0];
const l2 = L_POSITIONS[i][1];
const l3 = L_POSITIONS[i][2];
if (
curI + l1[0] < 0 ||
curI + l2[0] < 0 ||
curI + l3[0] < 0 ||
curI + l1[0] >= h ||
curI + l2[0] >= h ||
curI + l3[0] >= h ||
curJ + l1[1] < 0 ||
curJ + l2[1] < 0 ||
curJ + l3[1] < 0 ||
curJ + l1[1] >= w ||
curJ + l2[1] >= w ||
curJ + l3[1] >= w
)
continue;
if (
board[curI + l1[0]][curJ + l1[1]] !== "." ||
board[curI + l2[0]][curJ + l2[1]] !== "." ||
board[curI + l3[0]][curJ + l3[1]] !== "."
)
continue;
board[curI + l1[0]][curJ + l1[1]] =
board[curI + l2[0]][curJ + l2[1]] =
board[curI + l3[0]][curJ + l3[1]] =
"#";
ret += recursion(board, numOfL + 1);
board[curI + l1[0]][curJ + l1[1]] =
board[curI + l2[0]][curJ + l2[1]] =
board[curI + l3[0]][curJ + l3[1]] =
".";
}
return ret;
}
function getNumOfComma(w, h, board) {
let comma = 0;
for (let i = 0; i < h; i++) {
for (let j = 0; j < w; j++) {
if (board[i][j] === ".") comma++;
}
}
return comma;
}
function getCommaXY(board) {
for (let i = 0; i < h; i++) {
for (let j = 0; j < w; j++) {
if (board[i][j] === ".") return [i, j];
}
}
}
//기저사례: 게임판을 모두 덮은 경우
//문제: L자 모양을 현재 위치에 넣어 공간을 채울 수 있는지
//기저사례: 게임판을 모두 덮은 경우
//문제: L자 모양을 현재 위치에 넣어 공간을 채울 수 있는지