动态规划实例(三):硬币找零方案
2017-06-17 10:57
239 查看
问题:假设有m种面值不同的硬币,个个面值存于数组S ={S1,S2,… Sm}中,现在用这些硬币来找钱,各种硬币的使用个数不限。 求对于给定的钱数N,我们最多有几种不同的找钱方式。硬币的顺序并不重要。
例如,对于N = 4,S = {1,2,3},有四种方案:{1,1,1,1},{1,1,2},{2,2},{1, 3}。所以输出应该是4。对于N = 10,S = {2,5, 3,6},有五种解决办法:{2,2,2,2,2},{2,2,3,3},{2,2,6 },{2,3,5}和{5,5}。所以输出应该是5。
1)最优子结构
要算总数的解决方案,我们可以把所有的一整套解决方案在两组 (其实这个方法在组合数学中经常用到,要么包含某个元素要么不包含,用于递推公式等等,)。
1)解决方案不包含 第m种硬币(或Sm)。
2)解决方案包含至少一个 第m种硬币。
让数(S [] , M, N)是该函数来计算解的数目,则它可以表示为计数的总和(S [], M-1, N)和计数(S [],M,N-Sm)。
因此,这个问题具有最优子结构性质的问题。
2) 重叠子问题
具体实例及实现代码如下所示:
例如,对于N = 4,S = {1,2,3},有四种方案:{1,1,1,1},{1,1,2},{2,2},{1, 3}。所以输出应该是4。对于N = 10,S = {2,5, 3,6},有五种解决办法:{2,2,2,2,2},{2,2,3,3},{2,2,6 },{2,3,5}和{5,5}。所以输出应该是5。
1)最优子结构
要算总数的解决方案,我们可以把所有的一整套解决方案在两组 (其实这个方法在组合数学中经常用到,要么包含某个元素要么不包含,用于递推公式等等,)。
1)解决方案不包含 第m种硬币(或Sm)。
2)解决方案包含至少一个 第m种硬币。
让数(S [] , M, N)是该函数来计算解的数目,则它可以表示为计数的总和(S [], M-1, N)和计数(S [],M,N-Sm)。
因此,这个问题具有最优子结构性质的问题。
2) 重叠子问题
具体实例及实现代码如下所示:
/** * @Title: CoinChange.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-7 上午8:57:21 * @version V1.0 */ package dynamicprogramming; /** * @ClassName: CoinChange * @Description: 硬币找零 * @date 2017-6-7 上午8:57:21 * */ public class CoinChange { /** * * @Title: coinChangRecursion * @Description: 递归解决方案 * @param s 硬币集合 * @param m 硬币种类 * @param n 钱数额 * @return * @return int * @throws */ public static int coinChangRecursion(int[] s, int m, int n){ //边界条件判断 if(n == 0) return 1; if(n < 0) return 0; if(m <= 0) return 0; //递归 return coinChangRecursion(s, m - 1, n) + coinChangRecursion(s, m, n - s[m-1]); } /** * * @Title: coinChange * @Description: 动态规划 * @param s 硬币数组 * @param m 硬币种类 * @param n 钱总数 * @return * @return int * @throws */ public static int coinChange(int[] s, int m, int n){ int res1, res2; //初始化状态转移数组 int[][] tc = new int[n+1][m]; //初始化状态转移数组 for(int i = 0; i < m; i++){ tc[0][i] = 1; } for(int i = 1; i < n+1; i++){ for(int j = 0; j < m; j++){ //包含s[j]时的种类 res1 = (i-s[j] >= 0)? tc[i - s[j]][j]: 0; //不包含s[j]的方案 res2 = (j >= 1)?tc[i][j-1]:0; tc[i][j] = res1 + res2; } } return tc [m-1]; } /** * @Title: main * @Description: TODO * @param args * @return void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub int[] arr = {1, 2, 3}; int m = arr.length; int n = 4; System.out.println("使用递归求解硬币找零方案数为:" + coinChangRecursion(arr, m, n) ); System.out.println("使用动态规划求解硬币找零方案数为:" + coinChange(arr, m, n)); } }
相关文章推荐
- 动态规划实例(九):最小硬币找零数
- NYOJ - 995 - 硬币找零(动态规划-完全背包)
- 动态规划之硬币找零问题
- Java动态规划之硬币找零问题实现代码
- 动态规划在求解硬币问题中的应用(JAVA)--币制最大化、找零问题、硬币收集问题
- 动态规划:最少硬币找零问题、01背包问题、完全背包问题
- 硬币问题(字典最小序)-DAG动态规划问题
- 动态规划之最少硬币
- 硬币问题(DAG上的动态规划)
- 动态规划两题(矩形嵌套+硬币问题)P161-162
- C++动态规划之最长公子序列实例
- 动态规划思想之最小硬币分配数
- 动态规划应用—硬币组合问题
- 动态规划详细解析---及各类问题解决方案
- 算法笔记——硬币找零之找钱方案数
- DAG上的动态规划------硬币问题
- .NET实现热插拔功能(动态替换功用)方案实例
- 较难的动态规划问题——付款问题,面值任意,可找零
- 买鸡蛋问题(硬币找零所有方案)