[백준] Baekjoon Online Judge

문제
n가지 종류의 동전이 있다. 이 동전들을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다. 그러면서 동전의 개수가 최소가 되도록 하려고 한다. 각각의 동전은 몇 개라도 사용할 수 있다.
입력
첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는 각각의 동전의 가치가 주어진다. 동전의 가치는 100,000보다 작거나 같은 자연수이다. 가치가 같은 동전이 여러 번 주어질 수도 있다.
출력
첫째 줄에 사용한 동전의 최소 개수를 출력한다. 불가능한 경우에는 -1을 출력한다.
풀이
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;
unordered_set<int> coins;
vector<int> dp(10001, -1);
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
for (int i = 0; i < n; i++) {
int num;
cin >> num;
dp[num] = 1;
coins.insert(num);
}
for (int i = 1; i <= k; i++) {
if (dp[i] > 0) {
for (int coin : coins) {
int idx = coin + i;
// 범위 제한
if (idx > 10000) continue;
// 사용 동전의 최소 개수 갱신
if (dp[idx] == -1)
dp[idx] = dp[i] + 1;
else
dp[i + coin] = min(dp[i] + 1, dp[i + coin]);
}
}
}
cout << dp[k] << '\n';
return 0;
}
동전의 가치는 중복되어서 입력될 수 있고, 이 가치가 정렬되어 있을 필요성이 없기 때문에 unordered_set에 coin의 가치를 입력 받았다. 해당 동전과 같은 값들은 동전 하나로 표현할 수 있기에 dp[num]을 1로 초기화하도록 했다.
for (int i = 1; i <= k; i++) {
if (dp[i] > 0) {
for (int coin : coins) {
int idx = coin + i;
// 범위 제한
if (idx > 10000) continue;
// 사용 동전의 최소 개수 갱신
if (dp[idx] == -1)
dp[idx] = dp[i] + 1;
else
dp[i + coin] = min(dp[i] + 1, dp[i + coin]);
}
}
}
cout << dp[k] << '\n';
다이나믹 프로그래밍으로 각 값들을 표현하기 위해 필요한 동전의 수를 구하는 부분의 코드이다.
1원부터 k원까지 쭉 살펴보다가 dp[i]가 0보다 크다면 i는 동전으로 표현할 수 있는 값이다. i를 동전으로 표현할 수 있다면 i + (동전의 가치) 또한 동전으로 표현할 수 있다. 그렇기에 for문으로 i + (동전의 가치)에 필요한 동전의 수를 갱신하도록 했다. 이때 idx가 범위를 넘어갈 수도 있으므로 if문으로 범위 초과를 방지했다.
'백준 > C++' 카테고리의 다른 글
[Baekjoon/C++] 1890번 - 점프 (0) | 2024.04.15 |
---|---|
[Baekjoon/C++] 2493번 - 탑 (0) | 2024.04.14 |
[Baekjoon/C++] 11098번 - 첼시를 도와줘! (0) | 2024.04.12 |
[Baekjoon/C++] 11722번 - 가장 긴 감소하는 부분 수열 (0) | 2024.04.09 |
[Baekjoon/C++] 11055번 - 가장 큰 증가하는 부분 수열 (0) | 2024.04.08 |