[ 백준 ] 2591 / 숫자카드

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
87/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2591 / 숫자카드
 *
 * Kind :: Dynamic Programming
 *
 * Insight
 * - 카드 배열=1
 *   [1]
 *   카드 배열=12
 *   [1,2] | [12]
 *   카드 배열=123
 *   [1,2,3] | [12,3] | [1,23]
 *   + dp[1] = 1
 *     dp[2] = 2
 *     dp[3] = 3 = dp[1] + dp[2]
 *     # dp[i] = i 번째까지 가능한 카드 배열의 수
 *       L = len(카드 배열)
 *       dp[L] = 가능한 카드 배열의 수
 *
 * Point
 * - 현재까지 만든 카드 배열의 가능한 경우의 수를 안다면
 *   숫자카드를 추가해서 만들어지는 카드 배열의 가능한 경우의 수를 구할 수 있기에
 *   DP 문제라는 것을 빨리 알아챘으나...
 *   + 문제는 만들기 불가능한 경우이다!
 *     사용할 수 있는 카드 중에 0 이 없어서 만들지 못하는 카드 배열이 존재하게 된다!
 *     # 만들 수 없는 카드 배열 예시
 *       0
 *       40
 *       123300
 *       190
 *       -> 이 경우 답으로 0 을 출력해야 한다
 *
 * - 현재까지 만든 카드 배열에서 뒤의 2자리수를 잘 살펴보아야 한다
 *   + ...23
 *     [... + 2 + 3] | [... + 23]
 *     dp[i] = dp[i-1] + dp[i-2]
 *   + ...01
 *     [...0 + 1]
 *     dp[i] = dp[i-1]
 *   + ...00
 *     [...0 + 0] => 불가능
 *     [... + 00] => 불가능
 *   + ...40
 *     [... + 40] => 불가능
 *     [...4 + 0] => 불가능
 *   + ...30
 *     [... + 30]
 *     dp[i] = dp[i-2];
 *   + ...10
 *     [... + 10]
 *     dp[i] = dp[i-2]
 *     # 이를 일반화하면 다음과 같다
 *       ...pc
 *       c = 뒤에서 첫번째 숫자
 *       p = 뒤에서 두번째 숫자
 *
 *       c 가 0 이 아니면 dp[i] += dp[i-1]
 *       c 가 0 이 아니고 pc <= 34 면 dp[i] += dp[i-2]
 *
 *       c 가 0 이고 p 도 0 이면 불가능
 *       c 가 0 이고 p >= 4 이면 불가능
 *       c 가 0 이고 1 <= p <= 3 이면 dp[i] += dp[i-2]
 *
 * - 카드 배열을 만드는 중 dp[i] = 0 이 발견된 경우는
 *   카드 배열을 만들 수 없다는 뜻임을 주의하자
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <cstring>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    string D; cin >> D;

    // Control : Output
    /* 비어있는 카드 배열이거나 카드 배열 맨 앞 숫자가 0 인 경우 */
    if (D.empty() || D[0] == '0') {
        cout << 0 << endl; /* 만들기 불가능 */
        exit(0);
    }
    int L = D.length();
    /* 1자리 수의 카드 배열인 경우 (앞에서 맨 앞 숫자가 0 이 아님을 확인) */
    if (L == 1) {
        cout << 1 << endl; /* 가능한 경우의 수는 1개 */
        exit(0);
    }

    // Process
    int dp[L+1];
    memset(dp, 0, sizeof(dp)); /* 가능한 경우의 수 0 으로 초기화 */

    /* dp[0] = 1 인 이유는
     * 카드 배열=27 을 만들 때,
     * 빈 카드 배열에서 숫자카드 27 을 추가할 때,
     * dp[2] += dp[0] 이기 때문
     * 애초에 숫자카드 0 장으로 빈 카드 배열을 만드는 경우는
     * 각 카드가 0 장씩 쓰인것으로 생각할 수 있어서 가능한 경우의 수는 1가지임 */
    dp[0] = dp[1] = 1;
    for (int i=2; i<=L; i++) {
        /* ...pc */
        int c = D[i-1]-'0'; /* 뒤에서 첫번째 숫자 */
        int p = D[i-2]-'0'; /* 뒤에서 두번째 숫자 */

        /* c 가 0 이 아닌경우 */
        if (c != 0) {
            dp[i] += dp[i-1];
        }

        /* p 가 0 이 아니며 pc 가 34 이하인 경우 */
        if (p != 0 && 10*p+c <= 34) {
            dp[i] += dp[i-2];
        }

        /* i 번째까지의 카드 배열을 만들 수 없는 경우 */
        if (dp[i] == 0) {
            break;
        }
    }

    // Control : Output
    cout << dp[L] << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글