티스토리 뷰
목차
문제
n가지 종류의 동전이 있다.
각각의 동전이 나타내는 가치는 다르다.
이 동전을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다.
그 경우의 수를 구하시오.
각각의 동전은 몇 개라도 사용할 수 있다.
사용한 동전의 구성이 같은데, 순서만 다른 것은 같은 경우이다.
입력
첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000)
다음 n개의 줄에는 각각의 동전의 가치가 주어진다.
동전의 가치는 100,000보다 작거나 같은 자연수이다.
출력
첫째 줄에 경우의 수를 출력한다.
경우의 수는 $2^{31}$보다 작다.
풀이
무한히 많이 주어진 유한한 가치의 동전들로 특정 값을 만들 수 있는 경우의 수를 구하는 문제이다.
그러니까 예를 들면 동전이 두 종류(가치는 1, 5)가 있고 10이라는 값을 만들어 내려면
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), (1, 1, 1, 1, 1, 5), (5, 5)의 세 가지 경우의 수가 생기며,
같은 종류의 동전이지만 순서만 바뀐 것은 하나로 처리한다.
문제를 푸는 방식은 아래와 같다.
- 입력받은 동전의 가치를 기반으로 반복문을 돌면서 각 가치를 만들 수 있는 경우의 수를 구한다.
- dp 배열에 현재 동전으로 만들 수 있는 각 가치의 경우를 누적합으로 계산한다.
이를 기반으로 코드를 간단하게 살펴보면,
- 동전의 개수(n)와 목표 금액(k)을 입력받아 각각 coins와 dp 배열의 크기를 초기화하고 coins는 주어진 값으로 채운다.
- dp[0]은 1로 설정한다. 이는 만들어야 하는 가치가 0인 경우 아무 동전도 선택하지 않는 경우의 수가 하나 있기 때문이다.
- 각 동전에 대해 반복문을 돌면서 해당 동전의 가치부터 목표금액(k)까지 dp 값을 갱신한다.
이때 dp[j]에 dp[j - coins[i]]를 누적하며 더하는 이유는 j라는 가치를 만드는 방법에
현재 동전(coins[i])을 사용하는 경우를 추가하는 것이다. - 모든 동전에 대해 순회한 후 dp[k]를 출력한다.
Additional Explain
3번의 경우에 대해 조금 이해가 어려울 수 있는데, 조금 더 예를 들면 아래와 같은 로직을 사용하는 것이다.
먼저, 주어진 동전이 1, 2원 두 개라고 가정하고, 4원을 만드는 과정을 생각해 보자.
이때, 초기화된 dp 배열은 [1, 0, 0, 0, 0]와 같이 생겼다.
- 1원 동전 사용
반복문을 시작해 1원부터 사용해 보자. 현재 동전의 가치인 1원부터 목푯값인 4원까지 모든 경우에 대해
dp[j] += dp[j - 1]을 수행하면 된다.
- j = 1 → dp[1] += dp[0] → dp[1] = 1 (1원을 만드는 법은 1원 동전 한 개)
- j = 2 → dp[2] += dp[1] → dp[2] = 1 (2원을 만드는 법은 1원 동전 한 개)
- j = 3 → dp[3] += dp[2] → dp[3] = 1 (3원을 만드는 법은 1원 동전 한 개)
- j = 4 → dp[4] += dp[3] → dp[4] = 1 (4원을 만드는 법은 1원 동전 한 개)
순회가 끝나면 dp는 [1, 1, 1, 1, 1]로 갱신된다.
- 2원 동전 사용
계속해서 다음 동전인 2원 동전을 사용해 보자. 현재 동전의 가치인 2원부터 목푯값인 4원까지 계산을 수행한다.
- j = 2 → dp[2] += dp[0] → dp[2] = 2 (2원을 만드는 법은 1원 동전 두 개, 2원 동전 한 개)
- j = 3 → dp[3] += dp[1] → dp[3] = 2 (3원을 만드는 법은 1원 동전 세 개, 1원 동전 한 개 + 2원 동전 한 개)
- j = 4 → dp[4] += dp[2] → dp[4] = 3 (4원을 만드는 법은 1원 동전 네 개, 1원 동전 두 개 + 2원 동전 한 개, 2원 동전 두 개)
계산이 끝나면 최종적으로 dp는 [1, 1, 2, 2, 3]이 된다.
문제에서 주어진 조건은 dp[4]이므로, 3이 원하는 답이 되는 것이다.
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Prob2293 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
int[] coins = new int[n];
int[] dp = new int[k + 1];
for (int i = 0; i < n; i++) {
coins[i] = Integer.parseInt(br.readLine());
}
dp[0] = 1;
for (int i = 0; i < n; i++) {
for (int j = coins[i]; j <= k; j++) {
dp[j] += dp[j - coins[i]];
}
}
System.out.println(dp[k]);
}
}
Python
import sys
n, m = map(int, sys.stdin.readline().rstrip().split(" "))
memories = [0] + list(map(int, sys.stdin.readline().rstrip().split(" ")))
costs = [0] + list(map(int, sys.stdin.readline().rstrip().split(" ")))
sum_cost = sum(costs)
dp = [0] + [float("-inf") for _ in range(sum_cost)]
for i in range(1, n + 1):
for j in range(sum_cost, costs[i] - 1, -1):
dp[j] = max(dp[j], dp[j - costs[i]] + memories[i])
result = 0
for i in range(sum_cost + 1):
if dp[i] >= m:
result = i
break
print(result)
Performance
'Algorithm > Dynamic Programming' 카테고리의 다른 글
[Python]1463번, 1로 만들기 (0) | 2023.10.17 |
---|---|
[Python]9095번, 1, 2, 3 더하기 (0) | 2023.10.12 |
[Python]2839번, 설탕 배달 (0) | 2023.10.11 |
[Java+Python]1066번, 파일 합치기, DP&누적합 (0) | 2023.07.07 |
[Java+Python]12865번, 평범한 배낭 (2) | 2023.05.18 |
[Java+Python]9251번, LCS(Longest Common Subsequence) (1) | 2023.05.15 |
- Total
- Today
- Yesterday
- Backjoon
- Python
- 면접 준비
- 백준
- 칼이사
- 파이썬
- 중남미
- 동적계획법
- 기술면접
- 알고리즘
- 스트림
- 맛집
- 여행
- 유럽
- 세계여행
- a6000
- 스프링
- spring
- 지지
- RX100M5
- 자바
- BOJ
- 리스트
- 남미
- 유럽여행
- Algorithm
- 야경
- 세계일주
- java
- 세모
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |