換零錢

題目描述

  考慮僅用1分、5分、10分、25分和50分這5種硬幣支付某一個給定的金額。例如須要支付11分錢,有一個1分和一個10分、一個1分和一個5分、六個1分和一個5分、十一個1分這4種方式。請寫一個程序,計算一個給定的金額有幾種支付方式。注:假定支付0元有1種方式。java

1.1 輸入描述:

  輸入包含多組數據。每組數據包含一個正整數n(1≤n≤10000),即須要支付的金額。算法

1.2 輸出描述:

  對應每一組數據,輸出一個正整數,表示替換方式的種數。數組

1.3 輸入例子:

11
26
  •  

1.4 輸出例子:

4
13
  •  

2 解題思路

  假設硬幣的種類數組t={1,5,10,25,50},按大小排序。m表示選擇有0~m種硬幣能夠選擇,面值是t[0]、•••、t[m-1]。要換的錢的數目是n。本題可使用動態規劃算法解決。測試

2.1 遞歸方式

  假設有n錢待找零,當前能夠供選擇的方式爲m種,f(n,m)表示共的待找零方案,則有遞推公式: spa

f(n,m)=⎧⎩⎨10f(n−t[m−1],m)+f(n,m−1)n=0n<0orm≤0n>0andm>0.net

 

  當n=0,f(n,m)=1,表示已經找零完畢,再找0元只有一種方案。 
  當n<0表示這種方案找零不合理,不能完成找零操做,而m≤0說明找零尚未完成,可是已經沒有能夠供選擇的硬幣了。因此f(n,m)=0。 
  對於能夠找零,而且還有硬幣選擇的狀況找零有兩種方案。第一種是:選擇一個能夠選擇的最大面值的,剩下的錢再進行找零操做,同時硬幣種類的選擇方案沒有變化,即爲:f(n-t[m-1],m)。第二種是:如今和之後都不選擇本次能夠選擇的最大的硬幣面值,而後再進行找零操做。即f(n,m-1)。code

2.2 非遞歸方式

  假設有n錢待找零,當前能夠供選擇的方式爲m種,建立一個長度爲n+1的數組r,r[i]表示找零爲i的找零方法爲r[i]。初始時r的第一個元素爲1,其它元素都爲0,即r[0]=1,r[i≠0]=0。 
  步驟1、由於硬幣的面值都按大小排序,從最小的面值開始選擇,先選擇最小的一個t[0]。對於找零爲大於0的狀況只有從t[0]開始纔可能有找零的狀況。對於i≥t[0]有r[i]=r[i]+r[i-t[0]]。這是隻有一種硬幣能夠選擇的狀況。 
  步驟2、當有2種硬幣能夠選擇,在步驟一已經求出了只有一種硬幣可供選擇的狀況,如今能夠選擇第二種硬幣,那麼只有找零數i≥t[0]時才能夠選擇第二種硬幣,因此有r[i]=r[i]+r[i-t[1]]。 
  同理能夠求得有三、四、•••。具體實現詳見代碼。orm

3 算法實現

import java.util.Scanner;

/**
 * Declaration: All Rights Reserved !!!
 */
public class Main {

    // 硬幣能夠供選擇的面值
    private final static int[] T = {1, 5, 10, 25, 50};

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
//        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));
        while (scanner.hasNext()) {
            int n = scanner.nextInt();

//            System.out.println(exchange(n, T.length));
            System.out.println(exchange(n));
        }

        scanner.close();
    }


    /**
     * 解法一:遞歸解法
     * 找零操做
     *
     * @param n 當前要找的零錢數
     * @param m 能夠選擇的硬幣種類T[0]~T[m-1]
     * @return 不的找零數目
     */
    private static int exchange(int n, int m) {

        if (n == 0) {
            return 1;
        } else if (n < 0 || m <= 0) {
            return 0;
        } else {
            return exchange(n - T[m - 1], m) + exchange(n, m - 1);
        }
    }

    /**
     * 解法二:非遞歸解法
     * 找零操做
     *
     * @param n 當前要找的零錢數
     * @return 不的找零數目
     */
    private static long exchange(int n) {

        // 選擇long否則可能會超出int表達範圍
        long[] result = new long[n + 1];

        // 初始化
        result[0] = 1;

        // 每次增長一種硬幣,且比以前硬幣的面值大,計算加入新的硬幣後每一個數目的錢其找零數有多少種
        for (int t : T) {
            for (int j = t; j <= n; j++) {
                result[j] += result[j - t];
            }
        }
        return result[n];
    }
}
  •  

4 測試結果

這裏寫圖片描述

相關文章
相關標籤/搜索