ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Coin change problem
    카테고리 없음 2019. 12. 4. 20:24
    728x90

    Coin change problem은 어떤 잔돈을 만들 수 있는 동전의 조합의 수를 알아내는 문제입니다.
    앞에서 설명한 Minimum Coin Change Problem 문제와 함께, Dynamic Programming에서 주로 다뤄지는 문제입니다.

    조건

    • S = {1,2,3} 동전의 종류는 3개 1, 2, 3
    • 잔돈은 4
    • 잔돈 4를 만들 수 있는 동전종류의 조합의 수 (단, 여기서 동전의 순서는 무시한다.)

    github link ← 여기 클릭

    package com.tistory.skysign.MITOpenCourseWare.R5_Dynamic_Programming;
    
    // 코드 보시기 전에, 아래 유튜브 DP영상을 꼭 보시고 코드를 봐주세요.
    // https://www.youtube.com/watch?v=PafJOaMzstY
    
    public class MC_CoinCombination {
        public void d0(int[][] dp) {
            System.out.print("    ");
    
            for(int j=0; j<dp[0].length; ++j){
                System.out.printf("%3d ", j);
            }
            System.out.println();
    
            for(int i=0; i<dp.length; ++i){
                System.out.printf("%3d|", i);
                for(int j=0; j<dp[0].length; ++j){
                    System.out.printf("%3d ", dp[i][j]);
                }
                System.out.println();
            }
        }
    
        // S 가 동전의 종류
        // M이 동전 종류의 갯수
        // change 가 잔돈
        public int MC(int[] S, int M, int change) {
            // 배열의 인덱스가 코인의 종류, 잔돈의 크기와 같게 하기 위해서,
            // +1 씩 해줍니다.
            // 코인의 종류가 3개 이면, dp[3][] 까지 계산합니다.
            int[][] dp = new int[M+1][change+1];
    
            // #1 코인 0 이 있다고 가정하고,
            // change(0)을 만들 수 있는건, 0코인이 하나만 가능, 0,0 조합이나, 0,1 조합은 없다고 가정
            for(int i=0; i<M+1; ++i) {
                dp[i][0] = 1;
            }
    
            // #2 0코인을 가지고, 1~change 를 만드는 조합은 없으므로, 전부다 0
            for(int j=1; j<change+1; ++j) {
                dp[0][j] = 0;
            }
    
            // dp 배열의 의미에 대해서 알아 보겠습니다.
            // 첫줄(dp[0][])인 0 코인을 가지고 만들 수 있는 조합은 앞의 #1 과 #2 에서 초기화 했습니다.
            // 사실 #2는 0코인이라기 보다는, 코인1개와 잔돈이 같을 때, 동전조합의 갯수를 +1 해주기 위해서 사용합니다.
            // 이부분은 좀 복잡하니까, 뒤에서 좀더 설명하겠습니다.
            // dp[i][j] 는 0코인 부터 S[i-1]코인을 가지고, j을 만들 수 있는 조합의 수를 나타냅니다.
    
            // 예를 들어, {0, 1, 2} 코인을 가지고 잔돈(5)를 만들 수 있는 조합의 수를 찾아 내려면,
            // {0, 1}로 잔돈 5을 만들 수 있는 동전조합의 수 <-1 t1의 의미
            // {0, 1, 2}로 잔돈(5-2)를 만들 수 있는 동전 조합의 수 <- t2의 의미
            //    다만,t2를 계산할 때, dp[2][1] 과 같은 경우에 읍수가 나오는 경우가 있어서 > 0클 때만 dp[i][j-S[i1]]을 더합니다.
    
            // dp[][0] 컬럼에 1을 미리 assign 하는 것이 문제를 쉽게 풀 수 있는 방법입니다.
            // 예를 들어, dp[2][2]를 계산할 때, 즉, 0, 1, 2 코인을 가지고, 잔돈(2)를 만드는 방법
            // t1은 dp[1][2] 이 되어 1 (즉, (1, 1)조합의수 1개)
            // t2는 dp[2][0] 이 되어서, 1 (즉, (2) 조합의수 1개)
            // 따라서, dp[2][2]는 2가 됩니다.
    
            // 이어서 dp[2][3]과 dp[2][4]를 설명해 보면,
            // t1은 dp[1][3] 이 되고, 1(즉, (1, 1, 1)조합의수 1개)
            // t2는 dp[2][1] 이 되고, 1(즉, (2)조합의수 1개)
            // 따라서, dp[2][3]은 2가 되구요.
            // dp[2][4]는
            // t1은 dp[1][4] (1, 1, 1)조합의수 1개
            // t2는 dp[2][2] (1,1) (2) 조합의 수 2개 -> 이부분은 이렇게 볼 수 있는대, (1,1)(2) 가 (1,1,2)(2,2) 되는 것이죠
            // 따라서, dp[2][4]는 3이 됩니다.
    
            // 이 부분이 dp 프로그래밍의 핵심적인 부분입니다.
            // i 는 컬럼으로, 동전의 종류별
            // j 는 잔돈입니다.
            for(int i=1; i<M+1; ++i) {
                for(int j=1; j<change+1; ++j) {
                    int t1 = dp[i-1][j];
                    int t2 = (j - S[i-1] >= 0)? dp[i][j - S[i-1]]: 0;
                    dp[i][j] =  t1 + t2;
                }
            }
    
            d0(dp);
    
            return dp[M][change];
        }
    
        public static void main(String[] args) {
    //        int[]S = {1, 2, 3};
    //        int M = S.length;
    //        int change = 3;
    
    //        int[]S = {1, 2, 3, 4, 5};
    //        int M = S.length;
    //        int change = 5;
    
            int[]S = {1, 2, 3, 4, 5};
            int M = S.length;
            int change = 7;
    
            int r;
            MC_CoinCombination mc = new MC_CoinCombination();
    
            r = mc.MC(S, M, change);
            System.out.println(r);
        }
    }
    728x90
Designed by Tistory.