백준 11726 — 2×n 타일링: 마지막 타일을 기준으로 나누기

마지막 타일의 배치를 두 경우로 나누고 10007로 나눈 나머지를 누적한다.

  • 문제 풀이
  • DP

백준 11726 문제 보기

문제

백준 11726 2×n 타일링 문제와 나머지 출력 조건

1. 테이블 정의하기

D[i] = 2×i 직사각형을 채우는 방법의 수

2. 점화식 찾기

Text
D[N] =
 // N번재 사각형을 만드는 경우의 수는, 마지막 타일을 기준으로 서로 겹치지 않는 두 집합으로
 // 분할이 가능하다
 // D[N-1]: 맨 끝 타일이 (2x1)의 세로 타일인 경우
 // D[N-2]: 맨 끝 타일이 (2x2)로 가로 타일 두 개를 쌓은 형태인 경우
 D[N-1] + D[N-2]

즉,

Text
DP[N]의 모든 경우

├─ ① 마지막이 세로 타일
│      → 앞부분은 2×(N-1)
│      → DP[N-1]의 모든 경우

└─ ② 마지막이 가로 타일 2개
       → 앞부분은 2×(N-2)
       → DP[N-2]의 모든 경우

3. 초기값 정의하기

Text
DP[1] = 1; // 2 x 1 사각형을 채우는 방법
DP[2] = 2; // 2 x 2 사각형을 채우는 방법

4. 코드 구현하기

JavaScript
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const N = Number(fs.readFileSync(filePath, 'utf-8'));
 
function solution() {
    // 1.배열 생성하기
    const DP = Array.from({ length: N + 1 }).fill(0);
 
    // 2. 초기값 설정하기
    DP[1] = 1;
    DP[2] = 2;
 
    // 3. for문 순회하기
    for (let i = 3; i <= N; i++) {
        // 2 x i 의 사각형의 맨 끝 타일을 채우는 방법은 아래 두 개 밖에 없다.
        // 3-1) 맨 끝에 세로 타일이 오는 경우 (2 x 1) - DP[i - 1]
        // 3-2) 맨 끝에 가로 타일이 오는 경우 - DP[i - 2]
        DP[i] = (DP[i - 1] + DP[i - 2]) % 10007;
    }
 
    console.log(DP[N]);
}
 
solution();

“전체 경우를 마지막 선택에 따라 나누면 어떻게 나뉘지?” 라는 질문을 기반으로 생각해보자!!


출력 조건도 점화식에 반영하기

문제는 경우의 수를 10007로 나눈 나머지를 요구한다. 각 덧셈에서 나머지를 저장해도 마지막 결과의 나머지는 같다. 마지막에만 나누면 그 전에 JavaScript 정수 정밀도를 벗어날 수 있으므로 매 단계에서 나눈다.

복잡도

시간 O(N), DP 테이블 공간 O(N).

참고 자료

바킹독의 실전 알고리즘 0x10강 — 다이나믹 프로그래밍을 학습하며 작성한 메모를 바탕으로 정리했다. 포함된 이미지는 원본 학습 메모의 캡처다.