-
[다이나믹 프로그래밍] 문제 이름 : 효율적인 화폐 구성Algorithm/유형별 문제 풀기 2021. 12. 22. 13:39
문제 설명
N가지 종류의 화폐가 있을 때, 이 화폐들의 개수를 최소한으로 이용해서 그 가치의 합이 M원이 되도록 하려고 한다.
이때 각 화폐는 몇 개라도 사용할 수 있고, 사용한 화폐의 구성은 같지만 순서만 다른 것은 같은 경우로 구분한다.
입력 조건- 첫째 줄에 N, M이 주어진다. (1 <= N <= 100, 1 <= M <= 10,000)- 이후 N개의 줄에는 각 화폐의 가치가 주어진다. 화폐 가치는 10,000보다 작거나 같은 자연수이다.
출력 조건- 첫째 줄에 M원을 만들기 위한 최소한의 화폐 개수를 출력한다.- 불가능할 때는 -1을 출력한다.
사용 개념
다이나믹 프로그래밍
- 그리디에서 거스름돈 문제와 비슷한데, 주어진 화폐 단위에서 큰 단위가 작은 단위의 배수가 아니라는 점만 다르다.
- 따라서 그리디 알고리즘을 사용했던 것처럼 매번 가장 큰 화폐 단위부터 처리하는 방법으로는 해결할 수 없다.
문제 해결 아이디어
점화식을 작성해보면,
금액 i를 만들 수 있는 최소한의 화폐 개수 = aᵢ
화폐의 단위(가치) = k
위의 해당 점화식을 주어진 모든 화폐 단위(가치)에 대하여 차례대로 적용하면 된다.
이때 10,001은 특정 금액을 만들 수 있는 화폐 구성이 불가능하다는 의미 (M의 최대 크기가 10,000이므로 이보다 큰 수로 설정하면 됨)
코드
import java.util.*; public class Main { public static void main(String[] args) { Scanner kbd = new Scanner(System.in); int N = kbd.nextInt(); int M = kbd.nextInt(); // 화폐 단위(가치) 입력 int[] coins = new int[N]; for(int i = 0; i < N; i++) { coins[i] = kbd.nextInt(); } // 한 번 계산된 결과를 저장하기 위한 DP 테이블 초기화 // 방법1. for문 // 방법2. Arrays.fill() int[] d = new int[M+1]; Arrays.fill(d, 10001); // 다이나믹 프로그래밍 진행 (보텀업 방식) d[0] = 0; // 0원을 만들기 위해 필요한 최소한의 화폐 개수 for(int i = 0; i < N; i++) { // 모든 화폐 단위(가치)에 대하여 차례대로 반복함 for(int j = coins[i]; j <= M; j++) { // (i-k)원을 만드는 방법이 존재하는 경우 if(d[j - coins[i]] != 10001) { d[j] = Math.min(d[j], d[j-coins[i]]+1); } } } // 계산 결과 출력 if(d[M] == 10001) System.out.println(-1); // 최종적으로 M원을 만드는 방법이 없는 경우 else System.out.println(d[M]); } }
추가 개념 정리
*Java에서 배열의 값을 특정 값으로 설정하기
방법1. for문을 사용
방법2. Arrays.fill()을 사용
참고) https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Arrays.html
'Algorithm > 유형별 문제 풀기' 카테고리의 다른 글
[최단경로] 문제이름 : 미래도시 (0) 2022.01.11 [다이나믹 프로그래밍] 문제 이름 : 바닥 공사 (0) 2021.12.21 [다이나믹 프로그래밍] 문제 이름 : 개미 전사 (0) 2021.12.21 [다이나믹 프로그래밍] 문제 이름 : 1로 만들기 (0) 2021.11.24 [이진 탐색] 문제 이름 : 떡볶이 떡 만들기 - 파라메트릭 서치 (0) 2021.11.22