[ 백준 ] 9084 / 동전

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
153/228
post-thumbnail

# Appreciation

/*
 * Problem :: 9084 / 동전
 *
 * Kind :: Dynamic Programming
 *
 * Insight
 * - 전형적인 DP 문제이다
 *   + C[i] = i번째 동전의 금액
 *     dp[i][j] = 1~i 번째 동전으로 금액 j를 만드는 방법의 수
 *     라고 했을 때, 점화식은 아래와 같다
 *     # dp[i][j] = dp[i-1][j] + dp[i][j-C[i]] if j-C[i] >= 0
 *       -> 1~i 번째 동전으로 금액 j를 만드는 방법의 수
 *          =
 *          1~(i-1) 번째 동전으로 금액 j를 만드는 방법의 수 <= i번째 동전을 사용안한 방법의 수
 *          +
 *          1~i 번째 동전으로 금액 j-C[i]를 만드는 방법의 수 <= i번째 동전을 사용한 방법의 수
 *
 * Point
 * - 사실 입력에서 동전의 금액이 정렬되어 있지 않아도 상관없다
 *   + 오름차순, 내림차순 및 임의의 순서로 주어져도 DP 에는 아무런 영향이 없다
 *
 * - dp[i][j] 가 아닌 dp[j] 로도 풀 수 있다
 *   + i번째 동전으로 금액 1~j를 만드는 방법의 수를 구하면
 *     자연스레 dp[j] = 1~i 번째 동전으로 금액 j를 만드는 방법의 수가 된다
 *     # dp[j] 로 알고리즘을 짜면
 *       아래 코드에서 dp[i][j] = dp[i-1][j] 부분을 생략할 수 있다
 *       -> 점화식을 보면 dp[i-1][...], dp[i][...] 부분만 필요하고
 *          dp[0~(i-2)] 부분은 더이상 필요치 않다는 것을 알 수 있다
 *
 * - dp[i][0] = 1 이다
 *   + 2원, 3원 금액의 동전이 주어졌다고 하자
 *     금액 | 2 3 (사용된 동전의 개수)
 *       0 | 0 0
 *       1 | 0 0
 *       2 | 1 0
 *       3 | 0 1
 *       4 | 2 0
 *       5 | 1 1
 *       ...
 *       # 2 = 2*1 + 3*0
 *         3 = 2*0 + 3*1
 *         4 = 2*2 + 3*0
 *         5 = 2*1 + 3*1
 *         이므로
 *         0 = 2*0 + 3*0 도 1가지 방법으로 인정해주어야 한다
 *
 * - DP 배열과 순서를 맞추어 주기 위해
 *   동전의 금액을 저장하는 배열을 N+1 크기로 선언해서
 *   1~N 번째에 차례로 넣어주었다
 */

# Code

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

#include <iostream>
#include <cstring>
#include <algorithm>

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
    int T; cin >> T;

    while (T--) {
        int N; cin >> N;
        int C[N+1];
        for (int i=1; i<=N; i++) {
            cin >> C[i];
        }
        int M; cin >> M;

        // Process
        int dp[N+1][M+1];
        memset(dp, 0, sizeof(dp));
        for (int i=1; i<=N; i++) { /* i 번째 동전을 사용 */
            dp[i][0] = 1; /* 금액 0원을 만드는 방법은
                           * 각 금액별 동전들을 모두 0개씩 사용하는 방법밖에 없음 */
            for (int j=1; j<=M; j++) { /* 금액 j원을 만들기 */
                dp[i][j] += dp[i-1][j]; /* i 번째 동전을 사용하지 않고
                                         * 금액 j원을 만드는 방법 */
                if (j-C[i] >= 0) { /* j-C[i] >= 0 인 경우에 i 번째 동전 사용 가능 */
                    dp[i][j] += dp[i][j-C[i]]; /* i 번째 동전을 사용하여
                                                * 금액 j원을 만드는 방법 */
                }
            }
        }

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

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

0개의 댓글