본문 바로가기
코딩테스트 준비/백준

[백준] 3067번 - Coins [Java]

by mwzz6 2025. 2. 26.

https://www.acmicpc.net/problem/3067

 

[백준] 3067번 - Coins [Java]
[백준] 3067번 - Coins [Java]


1.  아이디어

 

무한 배낭 문제로 다이나믹 프로그래밍으로 해결할 수 있다.
직관적인 2차원 dp 테이블을 활용한 방식과 좀 더 발전한 1차원 dp 배열을 활용한 방식으로 해결했다.


2. 문제풀이

 

2차원 dp 테이블은 행을 동전의 번호, 열을 방법의 수로 하면 되고 1차원 dp 배열은 방법의 수를 인덱스로 하면 된다.

방법의 수는 현재 동전을 사용해서 만들 수 있는 경우의 수와 현재 동전을 사용하지 않고 만들 수 있는 경우의 수의 합으로 구할 수 있다.
2차원 dp 테이블의 경우 0원을 만들 수 있는 경우는 1가지이므로 모든 행의 0번 인덱스는 1로 초기화했다.
방법의 수를 구하기 위해 dp 테이블의 각 칸은 현재 동전을 사용하지 않고 만들 수 있는 경우의 수로 초기화 해준 뒤 현재 동전을 사용해서 만들 수 있는 방법의 수를 더해줬다.
현재 동전을 사용해서 만들 수 있는 방법의 수는 현재 동전의 액면가를 뺀 dp 테이블 위치에서 방법의 수가 존재하면 이걸 더해주면 된다.


1차원 dp 배열도 동일한 원리로 동전을 중복 사용할 수 있으므로 역순이 아닌 정방향으로 갱신을 해줬다.


3. 코드

 

import java.io.*;
import java.util.*;

public class Main_1D {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;

        int T = Integer.parseInt(br.readLine());
        for (int tc = 1; tc <= T; tc++) {
            int N = Integer.parseInt(br.readLine());

            int[] coins = new int[1 + N];
            st = new StringTokenizer(br.readLine());
            for (int i = 1; i <= N; i++) {
                coins[i] = Integer.parseInt(st.nextToken());
            }

            int M = Integer.parseInt(br.readLine());

            int[] dp = new int[1 + M];

            // 0원을 만들 수 있는 경우는 1가지
            dp[0] = 1;

            for (int i = 1; i <= N; i++) {
                // 중복 선택을 위해 앞에서부터 갱신
                for (int j = coins[i]; j <= M; j++) {
                    dp[j] += dp[j - coins[i]];
                }
            }

            sb.append(dp[M]).append("\n");
        }

        bw.write(sb.toString());
        bw.flush();
    }
}
import java.io.*;
import java.util.*;

public class Main_2D {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;

        int T = Integer.parseInt(br.readLine());
        for (int tc = 1; tc <= T; tc++) {
            int N = Integer.parseInt(br.readLine());

            int[] coins = new int[1 + N];
            st = new StringTokenizer(br.readLine());
            for (int i = 1; i <= N; i++) {
                coins[i] = Integer.parseInt(st.nextToken());
            }

            int M = Integer.parseInt(br.readLine());

            int[][] dp = new int[1 + N][1 + M];
            for (int i = 1; i <= N; i++) {
                // 0원을 만들 수 있는 경우는 1가지
                dp[i][0] = 1;

                for (int j = 1; j <= M; j++) {
                    dp[i][j] = dp[i - 1][j];
                    if (j >= coins[i]) dp[i][j] += dp[i][j - coins[i]];
                }
            }

            sb.append(dp[N][M]).append("\n");
        }

        bw.write(sb.toString());
        bw.flush();
    }
}

4. 후기

 

- 1차원 dp

- 2차원 dp