Algorithm
[C++] 백준 4781 사탕 가게 - Unbounded Knapsack (DP)
Rubi ❤️
2025. 3. 21. 00:08
728x90
반응형
백준 4782번 사탕 가게 문제는 정해진 예산 안에서 최대 칼로리를 얻는 방법을 찾는 문제로,
Unbounded Kapsack (중복 구매 가능) 유형의 전형적인 DP 문제 입니다.
🔍 문제 요약
문제 링크: 백준 4781번 사탕가게
- 목표: 총 예산
T
센트를 초과하지 않으면서 최대한 많은 칼로리의 사탕 구매 - 조건:
- 사탕 개수
N
(1 <= N <= 5,000) - 사탕 가격
P
, 사탕 칼로리C
- 사탕은 중복 구매 가능하다
- 사탕 개수
- 제한:
- T <= 10,000 센트 -> 100.00 달러에서 센트로 정수 전환 필요
- 출력:
- 최대로 얻을 수 있는 칼로리 값
1. 💡 문제 분석
- 무제한 중복 구매 가능 -> Unbounded Knapsack 문제
- 가격이 float(달러)로 주어짐 -> int(센트)처리
- 같은 사탕을 여러 번 살 수 있음.
2. 🔑 아이디어 도출
- 가격 단위를 센트 단위로 정수 변환
- DP 배열 사용
dp[i] = i
센트로 얻을 수 있는 최대 칼로리
- 점화식
dp[i] = max(dp[i], dp[i - price[j] + cal[j])
- 작은 예산부터 순서대로 채워서 중복 구매 효과 반영
현재 i센트 → 사탕 가격 K센트(price[j]) 사용 → 남는 돈 = i - K
이 때 얻는 칼로리 = dp[i - K] + 사탕 칼로리 = 남는 돈에 대한 칼로리 + 현재 구매한 사탕 칼로리
dp[i] = max(dp[i], dp[i - K] + 사탕 칼로리)
3. 🧩 풀이 전략
dp[T + 1 개]
배열 초기화- 각 사탕에 대한 가격, 칼로리 저장
price[5001]
,calories[5001]
- 모든 예산 i에 대해 사탕을 반복 사용 가능하도록 DP 수행
- 최종
dp[T]
값 출력
- 핵심 풀이
for (int i = 0; i <= total; ++i) { // 예산 i 센트를 기준으로
for (auto& candy : candies) { // 모든 사탕을 반복해서
if (i >= candy.first) { // i보다 가격이 작거나 같은 경우
dp[i] = max(dp[i], dp[i - candy.first] + candy.second);
}
}
}
- 예산이
i 센트
일 때- 각 사탕을 한 번씩 시도하면서
→ 해당 사탕 가격만큼 뺀dp[i - price]
에 사탕의 칼로리를 더해서
→ dp[i] 갱신 - 사탕을 반복해서 넣은 경우까지 포함됨
- 각 사탕을 한 번씩 시도하면서
📦 예제 입력 & 출력
- input
2 8.00
700 7.00
199 2.00
3 8.00
700 7.00
299 3.00
499 5.00
0 0.00
- output
796
798
4. ✅ 검증 및 테스트
- 시간 복잡도:
- DP
- O(N*T) = 5,000 * 10,000 = 50,000,000 -> 1초 이내
- 공간 복잡도:
dp[10001]
-> 약 40KB
🖥️ 코드
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[10001];
int price[5001];
int cal[5001];
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
while (1) {
int n;
double m;
cin >> n >> m;
if (n == 0 && m == 0.00)
break;
int m_cents = (int)(m * 100 + 0.5);
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++) {
double p;
cin >> cal[i] >> p;
price[i] = (int)(p * 100 + 0.5);
}
for (int i = 0; i < n; i++) { //사탕 종류
for (int j = price[i]; j <= m_cents; j++) {
dp[j] = max(dp[j], dp[j - price[i]] + cal[i]);
}
}
cout << dp[m_cents] << "\n";
}
return 0;
}
✨ 결론
- Unbounded Knapsack의 전형적인 DP 문제
- DP로 시간 초과 없이 해결 할 수 있다!
728x90
728x90
반응형