[C++] 백준 11052 [카드 구매하기]

date:

Updated:


Categories:

Tags: , ,

문제설명

카드팩 N개가 주어지고, 첫 번째 카드팩에는 1개의 카드가, 두 번째 카드팩에는 2개의 카드가, N 번째 카트팩에는 N개의 카드가 있다.
또한, 각 카드팩의 가격이 주어진다.
민규는 총 N개의 카드를 구매하려고 하는데, 이 때 지불해야하는 금액의 최대값을 출력하는 문제이다.

풀이방법

Top-down 풀이방식이다.
Cache array는 이중 배열로 구현하였다.
vector<int> card : 카드팩의 가격
DP(a, b)의 정의 : b까지의 카드팩에서 a개의 카드를 구매할 때 지불해야하는 금액의 최대값
문제의 정답은 DP(N,N)이 된다.
기저조건은 a 또는 b가 0인 경우이다.

만약, a보다 b가 큰 경우에는 카드팩을 선택할 수 없으므로, b-1 번째 카드팩까지 선택하는 것과 같다.(DP(a, b-1))
그 외의 경우, 현재 카드팩을 선택한 경우와 아닌경우 2가지로 나눌 수 있다.

1) 선택한 경우
구매해야 하는 카드의 수가 b만큼 줄어든다(b번째 카드팩에는 b개의 카드가 들어있다)
그리고 금액은 card[b]만큼 늘어난다.
그 후, 더 이상 b번째 카드팩을 선택 안하는 경우와, 선택할 수도 있는 2가지 경우가 생긴다.
1-1) 더 이상 b번째 카드팩을 선택하지 않는 경우
DP(a-b, b-1) + card[b]
1-2) b번째 카드 팩을 선택할 수도 있는 경우
DP(a-b, b) + card[b]

2) 선택하지 않은 경우
DP(a,b-1)

1-1, 1-2, 2 총 3가지의 경우 중 최대값이 DP(a,b)이다.

점화식

\(DP(a, b) = DP(a, b-1)\) (a < b 인 경우) \(DP(a, b) = max(DP(a, b-1), DP(a-b, b) + card[b], DP(a-b, b-1) + card[b])\)

위 점화식에 따라 코드를 작성하면 아래와 같다.

소스코드

#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

int N;
vector<int> card;
int cache[1001][1001];

int DP(int a, int b){
    if(a == 0) return 0;
    if(b == 0) return 0;
    
    int& ret = cache[a][b];
    if(ret != -1) return ret;

    if(a<b) return ret = DP(a,b-1);
    ret = max(max(DP(a-b, b) + card[b-1], DP(a,b-1)), DP(a-b, b-1) + card[b-1]);
    return ret;
}

int main(){
    cin >> N;
    memset(cache, -1, sizeof(cache));
    for(int i=0; i<N; i++){
        int n;
        cin >> n;
        card.push_back(n);
    }
    cout << DP(N, N);
}

Leave a comment