程序员面试金典: 9.9 递归和动态规划 9.8求n分可以由25分,10分,5分,1分的硬币的表示方法
2017-01-09 20:56
253 查看
#include <iostream> #include <stdio.h> using namespace std; /* 问题:给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。 分析:因为此题中的硬币数量满足,相邻面值中较高的设为h,较小的为l,有h>=2*l,则任意较高面值的可以→较低的面值表示 则简单的实现就是用贪心法来做。贪心满足两个原则: 1)贪心选择:全局最优解可通过局部最优解得到。每次选择,生成局部最优解,将问题转化为规模更小的子问题 2) 最优子结构:问题最优解包含其子问题最优解。 贪心的特点:必定按照从大较小或从小较大某种顺序来 证明贪心选择:设货币分别为P={p1,p2,..,pn},假设n>p1,选择p1, 选择的隐蔽集合是S1={p1},得到一个局部解,问题转化为在P1={p2,..,pn}中挑选货币支付n-p1 证明最优子结构:假设结果为Sn={p1,p2,p3,p4},子问题的最优解为 Sn-1={p2,p3,p4},有Sn-1U{p1}=Sn,即问题最优解包含子问题最优解 分析:假如n=1,那么必定只有1种 假如n=5,有两种:本身5,和用5个1表示 假如n=10,有5种:10,2个5,1个5和5个1,5个1和1个5,10个1 分析得到:f(10)=f(5)*f(5) + 设为n,则必定被<=n的最大的数表示,记为k1,k2,....,kn P = {p1,p2,..,pn} f(n) = f(k1)*f(k2)*...*f(kn) + n in P ? 1 : 0 其中满足k1+k2+...+kn=n,n>k1>=k2>=...>=kn f(1)= 1 f(5)=f(1)*f(1)*f(1)*f(1)*f(1) + 5 in P ? 1 : 0 = 1 * 1.. + 1 = 2 f(10)=f(5)*f(5)+1=5 f(25)=f(10)*f(10)*f(5)=5*5*2 + 1 = 51 f(9)=f(5)*f(1)*f(1)*f(1)*f(1) + 0 = 2 输入: 5 10 输出: 2 4 关键: 1 书上解法: 接下来分别求出在当前硬币值p下,分别用0个p面值的硬币,1个p面值的硬币,..., k个p面值的硬币(k*p <= n)情况下,传入下一个兑换值n 分别对上述情况继续兑换,直到当前硬币全用1表示,返回只有一种表示方式 下一个兑换面值采用switch传入的方法: switch(denom) { case 25: next_denom = 10; 2 int makeChange(int n , int denom) { int next_denom = 0; //根据当前传入的硬币值,确定下一次进行兑换的硬币值 switch(denom) { case 25: next_denom = 10; break; case 10: next_denom = 5; break; case 5: next_denom = 1; break; case 1: return 1; } // 接下来分别求出在当前硬币值p下,分别用0个p面值的硬币,1个p面值的硬币,..., k个p面值的硬币(k*p <= n)情况下,传入下一个兑换值n 分别对上述情况继续兑换,直到当前硬币全用1表示,返回只有一种表示方式 // int ways = 0; for(int i = 0 ; i * denom <= n ; i++) { //牛逼,假如n=50,那么等于(50,10),(25,10),(0,10),即分别采用0~2个25面值的硬币表示50面值,剩余的继续用于兑换 ways += makeChange(n - i * denom , next_denom); } return ways; } */ int makeChange(int n , int denom) { int next_denom = 0; //根据当前传入的硬币值,确定下一次进行兑换的硬币值 switch(denom) { case 25: next_denom = 10; break; case 10: next_denom = 5; break; case 5: next_denom = 1; break; case 1: return 1; } /* 接下来分别求出在当前硬币值p下,分别用0个p面值的硬币,1个p面值的硬币,..., k个p面值的硬币(k*p <= n)情况下,传入下一个兑换值n 分别对上述情况继续兑换,直到当前硬币全用1表示,返回只有一种表示方式 */ int ways = 0; for(int i = 0 ; i * denom <= n ; i++) { //牛逼,假如n=50,那么等于(50,10),(25,10),(0,10),即分别采用0~2个25面值的硬币表示50面值,剩余的继续用于兑换 ways += makeChange(n - i * denom , next_denom); } return ways; } void process() { int n; while(cin >> n) { int result = makeChange(n , 25); cout << result << endl; } } int main(int argc , char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- 9.9递归和动态规划(八)——给定数量不限的硬币,币值为25分,10分,5分,1分,计算n分有几种表示法
- 9.9递归和动态规划(八)——给定数量不限的硬币,币值为25分,10分,5分,1分,计算n分有几种表示法
- 币值为25分、10分、5分和1分的硬币,计算n分有几种表示方法
- 程序员面试金典(动态规划):1分,5分,10分,25分硬币面值组合问题(解题思路)
- 有数量不限的硬币,币值为25分、10分、5分和1分,请编写代码计算n分有几种表示法
- 换零钱:有数量不限的硬币,币值为25分、10分、5分和1分,请编写代码计算n分有几种表示法。
- 给定数量的币值,如25分,10分,5分,1分,编写计算n分的有多少种表示方法
- 给定数量不限的硬币,币值为25分,10分,5分和1分,编写代码计算n分有几种表示法
- 给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有多少种表示法。
- 有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,求有多少种组合可以组合成n分钱?
- 创新工场笔试题----有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,求有多少种组合可以组合成n分钱?
- 用递归实现,显示用1分、2分和5分的硬币凑成1元,一共有多少种方法。
- 程序员面试金典: 9.9 递归和动态规划 9.7颜色填充
- 程序员面试金典: 9.9 递归和动态规划 9.5求字符串的全排列
- 把一元硬币换成1分,2分5分的硬币有几种不同的方法
- 程序员面试金典: 9.9 递归和动态规划 9.1上楼的方式
- 一元的硬币分成1分,2分,5分的方法有多少种???
- 程序员面试金典: 9.9 递归和动态规划 9.11求布尔表达式的表达个数
- 程序员面试金典: 9.9 递归和动态规划 9.3魔术索引
- 程序员面试金典: 9.9 递归和动态规划 9.2机器人走路的方式