Python题解—最少硬币问题
最少硬币问题
题目描述
有 5 种硬币,面值分别为 1, 5, 10, 25, 50,数量无限。输入非负整数 S(S < 250) ,请你选用硬币,使其和为 S。要求输出最少的硬币组合。
问题分析:
- 这个问题上手确实令人很懵。这时我们必须要从小处开始找寻规律。1可以有1表示,2可以有1 1 表示,3可以由 2 1 继而由1 1 1 表示。求一个大数的最优解,一种可能是它直接就是相应面值的金额,那么一共只需要1枚硬币,可除此之外,它都是由一个最优子结构加上一枚硬币构成。所以,要完成对上层的优化,变成了一个子问题的最优化,这显然就是动态规划的原理,我们进而要将问题往动态规划上思考,去研究其递归关系。
- 从一个子结构,不断扩展。如果我们从输入的值倒推是困难的。如果我们从基础的往下推,把所有数值的最少硬币组合都表示出来。也就是所谓的“打表法”,以空间去换取时间。这是可行的,而且面对连续的输入这是极为高效的,因为我们只需要在储存的数组里查询即可。
- 本题还有一个问题是要输出硬币组合,所以在这个递归的过程中,我们必须进行过程的记录。对于每次往下推的过程中,我们将最后一枚放入组合的硬币存储起来,那么我们从而可以从递归关系中获取所有的硬币信息。
拟定计划:
- 使用数组储存最少硬币数量,将要组成的金额由数组的序列来表示。先定义一个初始值,设的大一点,开辟相应的内存空间。
- 我们从面值为1的硬币开始递归,直到面值为50的硬币也递归完成。递归规则:dp[i] = min(dp[i], dp[i - m] + 1)。在这个过程中要注意数组不能越界。
- 再定义一个数组来储存硬币组合关系,同样将要组成的金额由数组的序列来表示。这个完全可以放在递归过程中进行。
money = [1, 5, 10, 25, 50]
dp = [999] * 251
dp[0] = 0
design = [999] * 251
s = int(input())
for i in money:
for j in range(i, len(dp)):
#dp[j] = min(d[j], dp[j - i] + 1)
if dp[j - i] + 1 <= dp[j]:
dp[j] = dp[j - i] + 1
design[j] = i
list = []
if dp[s] < 999 :
while s > 0:
list.append(design[s])
s = s - design[s]
else:
print("no answer")
list.sort()
for i in list:
print(i, end=' ')
回顾反思:
- 这是我第一次认真地分析解决动态规划问题。还是相当有难度的。
- 我们要关注一点,一定要从简单的开始思考,从而发现规律,发现递归关系。这一点是动态规划很令人头疼的地方。
- 打表法,以空间换取时间。将所要的所有信息都储存起来,要使用的时候查询即可,这是一个很好的办法。
- 我们可以在递归的过程中存储关键信息,从而表述整个过程。
- 对于数组来说,其序列索引值也储存了一定的信息,我们常常会利用到这一点。

浙公网安备 33010602011771号