硬币找钱问题
与网易博客http://yixiong89921.blog.163.com/blog/static/132537788201137105357406/同步
问题描述
设有6种不同面值的硬币,各硬币的面值分别为5分,1角,2角,5角,1元,2元。现要用这些面值的硬币来购物和找钱。购物时规定了可以使用的各种面值的硬币个数。
假定商店里各面值的硬币有足够多,顾客也可用多种方式支付。在1次购物中希望使用最少硬币个数。例如,1次购物需要付款0.55元,没有5角的硬币,只好用2*20+10+5共4枚硬币来付款。如果付出1元,找回4角5分,同样需要4枚硬币。但是如果付出1.05元(1枚1元和1枚5分),找回5角,只需要3枚硬币。这个方案用的硬币个数最少。
您的任务:对于给定的各种面值的硬币个数和付款金额,计算使用硬币个数最少的交易方案。
输入
有若干行测试数据。每一行有6个整数a5、a4、a3、a2、a1、a0和1个有2位小数的实数money,分别表示5分,1角,2角,5角,1元,2元面值的硬币个数和付款金额,money<=1000。文件以6个0结束(不必处理)。
输出
对每一行测试数据,一行输出最少硬币个数。如果不可能完成交易,则输出“impossible”。
输入样例
2 4 2 2 1 0 0.95
2 4 2 0 1 0 0.55
0 0 0 0 0 0
输出样例
2
3
具体代码稍后放出。
4月12日更新代码,不好意思,CSDN的审核可能比较久……现在才出来http://download.csdn.net/source/3167555
其核心思想为消费者硬币数量有限,商店的硬币无限。因此问题可以用以下公式来描述
1、Min(消费者支付金币数量+商店找零金币数量);
2、支付值-找零值=商品值
寻找上面两个问题的最优解。
现在说说贪心算法的灵魂所在,下面会介绍为什么是这样。
这里所用的贪心算法为:MAX(消费者拥有的硬币面值-商店拥有的硬币面值)优先使用。
例如消费者拥有面值为2元的硬币,商店拥有5分的硬币,因此max=2元-5分=195分。那么上面所有的组合情况为
2元(不找零的情况),2元-5分,2元-1角,……,5分(不找零的情况)
现在假如我购买的商品是2元,那么用上面的组合中使用2元优先,只用1个硬币即可;假如商品是2元9角5分,我们从上面的序列中使用贪心算法来选择,那么就是一枚2元的硬币优先,那么9毛5如何处理呢,因为上面的序列中存在1元-5分存在的情况,这是能够使用的最大币值(贪心),就用它了,那么它是2枚硬币,即支付1元找零5分,总共用了3枚硬币。
接下来验证这个算法的贪心选择性和最优子结构性质,证明贪心算法可以获得最优解
贪心选择性:用贪心策略的选择替代原来的选择,如果能获得更优解或同优解,那么贪心策略就可以获得最优解。
我们把相应的序列列出来(用“分”来表示):
C[]={200,195,190,180,150,100,95,90,80,50,45,40,30,20,15,10,5};(除红色外其它面值都由两硬币之差构成)
证明这个序列具有贪心选择性质即可,这里我们先用一个简单的例子来证明
c[]={10,5,2,1},这里,c[i]的出现次数最多为{n,1,2,1},这样才能得到最优解,因为面值为1的次数为2时,可以用一个面值为2的来代替,硬币使用数就少了,那么就可以获得更优解。面值为2的硬币只能选用2个,若选用了3个,可以用1枚面值为5和一枚面值为1的硬币来代替。概括来讲,就是说如果c[i]超过一定数量,可以用更少的c[i-1]来代替,因此,我们优先选择大的面值的话,就会用更少的硬币数,因此满足贪心选择性质。
这里回归到我们问题的序列C[],容易看出C[i]总可以用更大的C[i-1]或者配合一些小币值来代替,但是数量<=C[i]的使用数量,因此满足贪心选择性质。当然这过程当中要考虑消费者硬币是否足够的问题
最优子结构性质证明:
设s[i]为各硬币使用数量,S[i]是商品价格为n时的最优解,硬币数为K,现在设某面值的硬币数量减一:S[j]=S[j]-1;则新的S[i]是n-c[j]的最优解,硬币数为k-1,否则,设T[i]是n-c[j]的最优解,硬币数为m,即m<k-1;那么对于n来说,T[i]的硬币数加1应该是最少的硬币数,即m+1<k-1+1=k,与k是最少硬币数矛盾,故问题满足最优子结构性质。
伪代码这里就不写了,如果是软院的同学~还是自己认真写一下吧~我的代码在4月8号公布~也就是明天,给以后不懂的同学参考吧,基本上没什么bug了。