타일링(DP)

2023. 8. 16. 14:53C++/알고리즘

https://school.programmers.co.kr/learn/courses/30/lessons/12900

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

DP 문제인만큼 이전의 상황들을 사용하여 새로운 상황을 풀어나간다.

 

길이가 N인 직사각형을 채우는 방법은 다음과 같이 나눌 수 있다.

1. 길이가 N-1인 직사각형을 채우는 방법에서 가장 오른쪽에 세로 타일 1개를 추가한다.

2. 길이가 N-2인 직사각형을 채우는 방법에서 가장 오른쪽에 가로 타일 2개를 추가한다.

 

길이가 N-2인 직사각형에서 세로 타일을 2개 추가하는 경우는 이미 1번에서 모두 나오게 된다.

 

DP[N] = DP[N-1] + DP[N-2]

 

#include <string>
#include <vector>

int DP[60001] = { 0, };

int solution(int n)
{
    DP[0] = 1;
    DP[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        // 바로 전 타일에서 세로타일 하나 추가
        // 전전 타일에서 가로타일 2개를 추가
        DP[i] = (DP[i - 1] + DP[i - 2]) % 1000000007;
    }
    int answer = DP[n];
    return answer;
}

https://school.programmers.co.kr/learn/courses/30/lessons/12902

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

가로의 길이가 3인 직사각형에선 고려해야할 사항이 추가로 생기게 된다.

 

1. 길이가 짝수일때만 타일을 채울 수 있다.

2. 길이가 4 이상일때 기존의 모양과 다른 형태의 타일 배열이 생기게 된다.

 

기본적인 타일의 배열은 다음 셋 중의 하나의 형태를 갖게된다.

 

그러므로 길이가 N-2인 직사각형을 채우는 경우의 수에서 3배를 곱하면 길이가 N인 직사각형을 채우는 경우의 수에 포함된다.

 

DP[N] = DP[N-2] * 3 + a

 

근데 길이가 4를 넘어가면 기존의 타일 배열로는 만들 수 없는 특이한 타일의 배열이 추가된다.

짝수 길이마다 이러한 특이한 배열은 2개씩 생겨나므로 N-4, N-6, N-8,...0까지 2배씩 곱하여 더해주어야 한다.

 

DP[N] = DP[N-2] * 3 + DP[N-4] * 2 + DP[N-6] * 2 + DP[N-8] * 2 + ... + DP[0] * 2

※DP[0] = 1, DP[2] = 3

 

이러한 점화식을 사용하여 문제를 정리하여 풀면 된다.

 

DP[N] = DP[N-2] * 3 + DP[N-4] * 2 + DP[N-6] * 2 + DP[N-8] * 2 + ... + DP[0] * 2

DP[N-2] = DP[N-4] * 3 + DP[N-6] * 2 + DP[N-8] * 2 + ... + DP[0] * 2

 

DP[N] = DP[N-2] * 3 + DP[N-2]

+ DP[N-4] * 2 + DP[N-6] * 2 + DP[N-8] * 2 + ... + DP[0] * 2

- (DP[N-4] * 3 + DP[N-6] * 2 + DP[N-8] * 2 + ... + DP[0] * 2)

 

DP[N] = DP[N-2] * 4 - DP[N-4]

 

저장되는 값은 1000000007로 나눈 값임에 유의하여야 한다

 

#include <string>
#include <vector>
using namespace std;

long long DP[5001] = { 0, };

int solution(int n)
{
    if (n % 2 == 1) return 0;
    DP[0] = 1;
    DP[2] = 3;
    // DP[n] = DP[n-2] * 3 + DP[n-4] * 2 + DP[n-6] * 2 +...+ DP[0] * 2
    // DP[n-2] = DP[n-4] * 3 + DP[n-6] * 2 +...+ DP[0] * 2
    // DP[n] = DP[n-2] * 4 - DP[n-4]
    for (int i = 4; i <= n; i += 2)
    {
        if (DP[i - 2] < DP[i - 4]) DP[i-2] += 1000000007;
        DP[i] = (DP[i - 2] * 4 - DP[i - 4]) % 1000000007;
    }
    return (int)DP[n];
}

'C++ > 알고리즘' 카테고리의 다른 글

경주로 건설(DP)  (0) 2023.09.05
숫자 게임(BST)  (0) 2023.08.18
수식 최대화(순열, 완전 탐색)  (0) 2023.08.08
광물 캐기(그리디)  (0) 2023.08.04
의상(해시, 조합 접근법)  (0) 2023.07.21