您的位置:首页 > 职场人生

程序员面试金典: 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐