2xn 타일링 Pgs#12900
2xN 타일링 PGs#12900
Python 코드 보기
def _2x2_matrix_multi(a,b):
new = [[0,0],[0,0]]
for i in range(0,2):
for j in range(0,2):
for k in range(0,2):
new[i][j] += a[i][k] * b[k][j]
return new
def nth_2x2_fiboMatrix(fiboMatrix,n):
k = 0
new = [[1,0],[0,1]] # 항등원
tmp = fiboMatrix.copy()
while (2**k <= n):
if n & (1 << k) != 0: # 6번째 -> 2^2, 2^1번째의 곱 이므로!!
new = _2x2_matrix_multi(new,tmp)
k += 1
tmp = _2x2_matrix_multi(tmp,tmp) # 매 while문 마다 2배수씩 늘어남
return new
def solution(n):
answer = 0
fiboMatrix = [[1,1],[1,0]] # [[fn+1, fn], [fn, fn-1]]
return nth_2x2_fiboMatrix(fiboMatrix,n+1)[0][1] % 1000000007
가로 길이가 2이고 세로의 길이가 1인 직사각형모양의 타일이 있습니다. 이 직사각형 타일을 이용하여 세로의 길이가 2이고 가로의 길이가 n인 바닥을 가득 채우려고 합니다. 타일을 채울 때는 다음과 같이 2가지 방법이 있습니다.
- 타일을 가로로 배치 하는 경우
- 타일을 세로로 배치 하는 경우
☝ 입력 형식
직사각형의 가로의 길이 n
이 매개변수로 주어집니다.
제한사항
- 가로의 길이
n
은 60,000이하의 자연수 입니다. - 경우의 수가 많아 질 수 있으므로, 경우의 수를 1,000,000,007으로 나눈 나머지를 return해주세요.
🤞 출력 형식
- 이 직사각형을 채우는 방법의 수를 return 하는 solution 함수를 완성해주세요.
🤟 구현 과정
1. 2x2 행렬의 곱 구현
2x2행렬의 곱을 수행하는 _2x2_matrix_multi()
함수를 정의해주었다.
matrix의 정의를 조금 수정해 가변형으로 정의하거나, 3중 for문의 범위를 2
가 아닌 행렬의 크기, size
를 받아 연산을 수행하면 더 큰 행렬에 대해서도 사용할 수 있다.
2. n번째 피보나치 수를 포함한 행렬 찾기
n번째 피보나치 수를 포함하는 행렬을 찾기 위해, nth_2x2_fiboMatrix()
를 정의하였다.
if n & (1 << k) != 0:
new = _2x2_matrix_multi(new,tmp)
해당 정의의 if n & (1 << k) != 0:
부분이 가장 직관적이지 못한데, 이는 매 while문 시행마다 tmp가 제곱수로 늘어나는 식으로 구현되었기 때문이다.
즉, 매 시행마다 tmp는 자기 자신과 곱해지므로,항상 k번째 시행되는 while문에서 아래와 같은 꼴로 존재한다.
\[\begin{pmatrix} F_{2^k+1} & F_{2^k} \\ F_{2^k} & F_{2^k-1} \end{pmatrix}\]이 때, 2k이 n을 2의 배수의 합으로 나타내는데 사용되는 값이라면 누적하여 곱해주는 방식이다.
예를 들어 n=6이라면, 2k=4,2일 때, 즉 k=2,1일 때 누적하여 곱해진다는 이야기다.
3. solution 구현
솔루션 함수는 그다지 구현이 필요하지 않다.
단순히 nth_2x2_fiboMatrix()
에 값을 넣고, 1,000,000,007로 나눈 값을 return하기만 하면 된다.
🍀 Pain Points
1. 시간 복잡도
O(N)의 시간 복잡도를 갖는 DP방식으로 설계한 기존의 피보나치 알고리즘으로는 마지막 효율성 검사에서 시간초과가 발생하였다.
O(N)보다 더 작은 시간 복잡도를 갖는 피보나치 알고리즘을 찾아보니, O(logN)을 갖는 방법을 2가지 정도 더 알 수 있었다. 참고한 사이트를 링크해두었다.
일반항을 이용하여 값을 계산하면 더 쉽게 값을 찾을 수 있을 것 같았으나, numerical result out of range
에러가 발생하여 일반항으로는 계산 할 수 없었다.
행렬의 곱을 이용한 피보나치 알고리즘은 처음 계산해보았으나, 기존의 DP를 이용했을 때와 메모리나 소요 시간을 비교해보니 비교가 무색할정도로 복잡도가 줄어들었음을 알 수 있었다.
참고한 사이트
댓글남기기