비대칭 타일링
문제
2xn 크기의 직사각형을 2x1크기의 타일로 채우려고 한다. 타일은 겹쳐서는 안 되고, 90도로 회전하여 사용이 가능하며 결과가 좌우 대칭이어서는 안 된다. n이 주어질 때 가능한 비대칭 타일링 방법의 수를 계산하는 프로그램을 작성하세요. 결과값은 1,000,000,007로 나눈 나머지를 출력합니다.
입력
첫 줄에는 테스트 케이스의 수 C(1~50)가 주어짐
다음 줄부터 사각형 너비 N(1~100)이 주어짐
예제 입력 및 출력
입력
3
2
4
92
출력
0
2
913227494
소스코드
#include <iostream>
#include <vector>
using namespace std;
int Case;
int cache1[101]; //넓이가 width인 직사각형을 무작위로 채우는 경우의 수 저장
int cache2[101]; //넓이가 width인 직사각형을 대칭이 아니게 채우는 경우의 수 저장
const int mod = 1000000007;
class tile {
private:
int recwidth;
public:
void Input() {
cin >> recwidth;
}
int getwidth() {
return recwidth;
}
//타일을 무작위로 채우는 경우의 수 구하는 함수
int tiling(int width) {
//타일을 다 채웠다면 1반환
if (width <= 1)
return 1;
//cache값 있으면 반환(현재 넓이의 사각형을 채우는 경우의 수는 이미 계산되었다)
if (cache1[width] != -1)
return cache1[width];
//현재 넓이의 사각형 채우는 경우의 수 계산
cache1[width] = (tiling(width - 1) + tiling(width - 2)) % mod;
return cache1[width];
}
//타일을 대칭이 아니도록 채우는 경우의 수 구하는 함수
int symmetry(int width) {
//타일이 2칸 이하로 남으면 0반환
if (width <= 2)
return 0;
//cache값 있으면 반환
if (cache2[width] != -1)
return cache2[width];
cache2[width] = (symmetry(width - 2)) % mod; //양쪽 2x1 타일을 붙인 경우
cache2[width] = (cache2[width] + symmetry(width - 4)) % mod; //양쪽 2x2 타일을 붙인 경우
//양쪽에 2x1 2x2 / 2x2 2x1타일을 붙인 경우 ->바로 모든 경우의 수
cache2[width] = (cache2[width] + tiling(width - 3)) % mod;
cache2[width] = (cache2[width] + tiling(width - 3)) % mod;
return cache2[width];
}
};
tile* mytile;
int main(void) {
cin >> Case;
mytile = new tile[Case];
for (int i = 0; i < Case; i++) {
mytile[i].Input();
}
for (int i = 0; i < Case; i++) {
memset(cache1, -1, sizeof(cache1));
memset(cache2, -1, sizeof(cache2));
cout << mytile[i].symmetry(mytile[i].getwidth()) << endl;
}
return 0;
}
문제 풀이
1. 문제 해결 전략
-
양쪽에 2x2타일을 붙이거나 2x1타일을 붙인 경우 -> 내부 타일을 어떻게 붙이는지에 따라 대칭이 될 수도 있고 비대칭이 될 수도 있다. -> 회색 부분 넓이를 인자로 전달하여 symmety함수를 재귀 호출한다.
-
양쪽에 2x1, 2x2 타일을 하나씩 붙인 경우 -> 내부 타일 모양에 상관없이 무조건 비대칭 타일이 된다. -> 회색 부분 넓이를 tiling함수에 전달하면 타일을 붙일 수 있는 모든 경우의 수를 알 수 있다.
2. cache값 이용
-
cache1[width] = 넓이가 width인 사각형에 타일을 무작위로 배치해 채우는 경우의 수
-
cache2[width] = 넓이가 width인 사각형에 타일을 비대칭이 되도록 채우는 경우의 수
3. 기저 사례
-
cache값이 이미 계산되었으면 바로 반환
4. 함수 탈출 조건
-
tiling함수 탈출 조건 : width가 1인 경우 2x1사각형 채우고 1반환, width가 0인 경우 바로 1 반환
-
symmetry함수 탈출 조건 : width가 2 인경우 2x1사각형 2개를 채워야 하는데 그럼 전체가 대칭이 되므로 0 반환, width가 1 인 경우 사각형을 다 채울 수 없는 배치 방법으로 0을 반환, wid가 0인 경우 전체가 대칭인 경우이므로 0 반환
5. 점화식
-
tiling 함수
-
cache1[width] = tiling(width-1) + tiling(width-2)
-
현재 넓이의 사각형을 무작위로 타일링 하는 경우의 수는 2x1사각형 한 개를 채우고 width-1을 다시 타일링하는 경우의 수 + 2x2사각형을 채우고 width-2를 다시 타일링 하는 경우의 수
-
-
symmetry 함수
-
cache2[width] = symmetry(width-2) // 양쪽에 2x1사각형을 붙이고 width-2를 비대칭 타일링
-
cache2[width] += symmetry(width-4) // 양쪽에 2x2사각형을 붙이고 width-4를 비대칭 타일링
-
cache2[width] += tiling(width-3) // 양쪽에 2x1 2x2 사각형을 붙이고 width-3을 무작위 타일링(2회 반복)
-