[ 백준 ] 4781 / 사탕 가게

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
162/228
post-thumbnail
post-custom-banner

# Appreciation

/*
 * Problem :: 4781 / 사탕 가게
 *
 * Kind :: Dynamic programming
 *
 * Insight
 * - 전형적인 냅색(Knapsack) 문제중 하나
 *   + Unbounded Knapsack Problem
 *     물건의 개수가 무한하고 쪼갤 수 없음
 *     # dp[i][j] = 1~i 번째 사탕을 사용해서 j 만큼의 돈을 구매했을 때 최대 칼로리 양
 *
 * - 사실 이 문제의 어려운점은 DP 가 아니다...
 *   + 돈의 양(배낭의 무게)이 소수점 2자리의 실수다!!!
 *     # 100을 곱하면 되지 않나?
 *       -> 그렇게 간단할 리가 없지...
 *
 * - 부동소수점의 무시무시함을 다시 느끼고 가자
 *   + 알아낸 바는 다음과 같다
 *     #  0.35 == 0.01 * 35   => false
 *       99.99 == 0.01 * 9999 => false
 *     #  0.35 == stod("0.35")  => true
 *       99.99 == stod("99.99") => true
 *     # (int)(0.29 * 100)  => 28
 *       (int)(81.85 * 100) => 8184
 *     # cout << fixed;
 *       cout.precision(20)
 *       로 설정하면
 *       -> cout << 0.29        => 0.28999999999999998002
 *          cout << 0.35 * 100  => 28.99999999999999644729
 *       -> cout << 81.85       => 81.84999999999999431566
 *          cout << 81.85 * 100 => 8184.99999999999909050530
 *
 * Point
 * - 그러니...
 *   round(반올림) 해주자
 *
 * - double 이 너무 무서워져서 <= 0.0 은 0 과 같은가? <= true
 *   string 으로 받고 stod 했다...
 */

# Code

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

#include <iostream>
#include <cmath>
#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
    int N; string m;
    while (true) {
        cin >> N >> m;
        if (N == 0 && m == "0.00") break;
        int M = (int)(round(stod(m)*100));

        int C[N+1], P[N+1];
        for (int i=1; i<=N; i++) {
            int c; string p;
            cin >> c >> p;
            C[i] = c;
            P[i] = (int)(round(stod(p)*100));
        }

        // Process
        int dp[N+1][M+1];
        memset(dp, 0, sizeof(dp));
        for (int i=1; i<=N; i++) {
            for (int j=1; j<=M; j++) {
                /* 1~(i-1) 번째 사탕을 사용해서 j 만큼의 돈을 구매했을 때 최대 칼로리 양 */
                dp[i][j] = dp[i-1][j];
                /* 1~i 번째 사탕을 사용해서 j 만큼의 돈을 구매했을 때 최대 칼로리 양과 비교 */
                if (j-P[i] >= 0) {
                    dp[i][j] = max(dp[i][j], dp[i][j-P[i]]+C[i]);
                }
                /* 위의 코드와 아래 코드의 로직은 같음
                 * 위의 코드의 경우는 Unbounded 일때 적용 <= 개수가 무한임
                 * 아래 코드의 경우는 Bounded   일때 적용 <= 개수가 한정됨
                 * 여기서는 k 로 돈이 허락하는 한 사탕을 최대한 많이 구매하게끔하여
                 * UnBounded 를 흉내냄 */
//              for (int k=1; k<=j/P[i]; k++) {
//                  dp[i][j] = max(dp[i][j], dp[i-1][j-k*P[i]]+k*C[i]);
//              }
            }
        }

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

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

0개의 댓글