您的位置:首页 > 编程语言

【编程马拉松】【023-换零钱】

2016-07-07 11:22 281 查看

【编程马拉松算法目录】

【023-换零钱】【工程下载>>>】

1 题目描述

  考虑仅用1分、5分、10分、25分和50分这5种硬币支付某一个给定的金额。例如需要支付11分钱,有一个1分和一个10分、一个1分和一个5分、六个1分和一个5分、十一个1分这4种方式。请写一个程序,计算一个给定的金额有几种支付方式。注:假定支付0元有1种方式。

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)表示共的待找零方案,则有递推公式:

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

  当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)。

2.2 非递归方式

  假设有n钱待找零,当前可以供选择的方式为m种,创建一个长度为n+1的数组r,r[i]表示找零为i的找零方法为r[i]。初始时r的第一个元素为1,其它元素都为0,即r[0]=1,r[i≠0]=0。

  步骤一、因为硬币的面值都按大小排序,从最小的面值开始选择,先选择最小的一个t[0]。对于找零为大于0的情况只有从t[0]开始才可能有找零的情况。对于i≥t[0]有r[i]=r[i]+r[i-t[0]]。这是只有一种硬币可以选择的情况。

  步骤二、当有2种硬币可以选择,在步骤一已经求出了只有一种硬币可供选择的情况,现在可以选择第二种硬币,那么只有找零数i≥t[0]时才可以选择第二种硬币,所以有r[i]=r[i]+r[i-t[1]]。

  同理可以求得有3、4、•••。具体实现详见代码。

3 算法实现

import java.util.Scanner;

/**
* Author: 王俊超
* Time: 2016-05-13 15:15
* CSDN: http://blog.csdn.net/derrantcm * Github: https://github.com/Wang-Jun-Chao * 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
;
}
}


4 测试结果



5 其它信息

因为markddow不好编辑,因此将文档的图片上传以供阅读。Pdf和Word文档可以在Github上进行【下载>>>】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: