• Home
  • About
    • Jang photo

      Jang

      Jang's blog

    • Learn More
    • Email
    • Facebook
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

(ALGO) 백준 2294번 문제 - 동전 2 문제(C++)

24 Jun 2018

Reading time ~2 minutes

2294

다이나믹 프로그래밍(Dynamic Programming, DP) 문제이다.

절차

  1. 가장 먼저 우리가 구하고자 하는 해답 함수를 정의한다.
    • coin(n, k) 함수의 정의 : n번째 동전부터 마지막 동전(N-1번째 동전)을 가지고 k를 만들 수 있는 최소 경우의 수. 즉, 해답은 coin(0,K)가 된다.
  2. 해답 함수에 대한 점화식을 정의한다.
    • 점화식: coin(n,k) = min(coin(n+1, k), coin(n, k-cost[n])+1)
    • 자세한 설명은 소스 코드 주석에 첨부
  3. 점화식이 주어진 조건을 벗어났을 경우를 정의한다.
    • case 1. k < 0: 동전 값은 양수이므로 k가 음수인 경우는 절대로 만들 수 없다. 따라서 무한한 값(INF)로 초기화 시켜준다.
    • case 2. n == N 이고 k == 0 (n==N의 의미는 N번째 동전부터 N-1번째 동전을 가지고 있다는 것인데, 이는 동전이 하나도 없다는 것과 같은 의미이다. ): 동전이 하나도 없을 때 k == 0을 만들 수 있는 최소 경우의 수는 0이다.(즉, 동전을 하나도 선택하지 않는 방법이 최소)
    • case 3. n == N 이고 k != 0: 동전이 하나도 없는데 0이 아닌 k를 만드는 것은 불가능하다. 따라서 무한한 값(INF)으로 초기화 시켜줌.
  4. 주어진 점화식을 memoization 시킨다(배열에 기록 한다). 만약 구하려는 n,k의 coin값이 이미 기록되어 있으면, 기록된 값을 반환한다.

소스코드 및 설명

설명은 주석에 첨부했습니다.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 절대 나올 수 없는 무한한 값으로 가정한다.
int INF = 10000000;

// memoization을 위한 101*10001(N의 최대값*K의 최대값) 크기의 mem 배열 선언 후 -1로 초기화
vector<vector<int>> mem(101, vector<int>(10001, -1));
// 입력받은 가격 값
vector<int> cost(101);
// 입력받은 N과 K
int N,K;

// coin의 정의 : n번째 동전부터 마지막 동전(N-1번째 동전)을 가지고 k를 만들 수 있는 최소 경우의 수. 즉, 해답은 coin(0,K)가 된다.
int coin(int n, int k)
{
    // case 1. k < 0: 동전 값은 양수이므로 k가 음수인 경우는 절대로 만들 수 없다. 따라서 무한한 값(INF)로 초기화 시켜준다.
    if(k < 0)
        return INF;

    // n == N이라는 것은 N번째 동전부터 N-1번째 동전을 가지고 있다는 것인데, 이는 동전이 하나도 없다는 것과 같은 의미이다.
    // case 2. n == N 이고 k == 0: 동전이 하나도 없을 때 k==0을 만들 수 있는 최소 경우의 수는 0이다.(즉, 동전을 하나도 선택하지 않는 방법이 최소)
    // case 3. n == N 이고 k != 0: 동전이 하나도 없는데 0이 아닌 k를 만드는 것은 불가능하다. 따라서 무한한 값(INF)으로 초기화 시켜줌.
    if(n == N)
        return (k == 0) ? 0 : INF;

    if(mem[n][k] != -1)
        return mem[n][k];

    // 1. n번째 ~ N-1번째 동전을 가지고 k를 만들 수 있는 최소 경우의 수: coin(n, k-cost[n])+1
    // 2. n+1번째 ~ N-1번째 동전을 가지고 k를 만들 수 있는 최소 경우의 수: coin(n+1, k)
    // 위 두 가지 중에 더 최소가 되는 값이 coin(n,k)의 해답이 된다. 즉, 최소 경우의 수를 찾아내기 위해선 n번째 동전을 가지고 있는 것이 좋은지 아닌지 판단한다.
    mem[n][k] = min(coin(n+1, k), coin(n, k-cost[n])+1);

    return mem[n][k];
}
int main()
{
    cin>>N>>K;

    for(int i=0;i<N;i++)
        cin>>cost[i];

    int re = coin(0,K);

    if(re == INF)
        re = -1;

    cout<<re<<endl;

    return 0;
}


algorithm Share Tweet +1