1、题目描述
本题是2019腾讯实习生笔试编程题第一题,也是NOIP2016 模拟赛的原题。题目是这样的:有 n 种不同面值的硬币,每种硬币有无限多个。为了方便购物,希望带尽量少的硬币,但是要能组合出 1 到 m 之间的任意值。
2、解题思路
首先判断有无解,如果最小面额硬币大于1则无解,因为搭配不出1。如果有1则有解,因为所有面额都可以由1堆积出来。 接下来思考一个问题,假设当前硬币可以组合出1到5的任意面额,那么添加一枚面额为6的硬币就可以搭配出1到11的任意面额。
考虑1 ~ i - 1已经构出,那么再加一枚什么面值的硬币最优,显然选一枚<=sum+1且面值最大的即可。面值最大保证了硬币数最小。sum表示硬币面值和。事实上,这个贪心可以从F[i] = F[i−A[k]] + 1 看出。F[i]必然是单调增的,因此贪心即可。F[i]表示处理完1−i的最少硬币数
于是我们依照这个思路,假设当前硬币面值的和为sum,每一次添加硬币时,从大到小搜索,将搜索到的第一枚面值小于等于sum+1的硬币加入,并将计数器+1,更新sum值,如果sum的值大于等于m的值,则查找结束。代码如下: