换零钱

题目描述

  考虑仅用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 测试结果

这里写图片描述

相关文章
相关标签/搜索