引言
找零问题:兑换最少个数的硬币
贪心策略:每次以最多数量的最大面值的硬币来迅速减少找零面值,若有余额,再到下一个最大面值的硬币,还用尽量多的数量,逐面值查找,直接面值为1结束。
递归条件
基本结束条件:需要兑换的找零,其面值正好等于某种硬币的数倍,没有余额。
减小问题的规模:对每种硬币尝试一次,分别将找零减去1、5、10、25后,求兑换硬币的最少数量(递归调用自身)。
代码实现一:
def recMC(coinvaluelist,change):
mincoins=change
if change in coinvaluelist:
return 1
else:
for i in [c for c in coinvaluelist if c<=change]:
numcoins=1+recMC(coinvaluelist,change-i)
if numcoins<mincoins:
mincoins=numcoins
return mincoins
print (recMC([1,5,10,25],63))
##记录运行时间:
import time
print(time.clock())
print (recMC([1,5,10,25],63))
print(time.clock())
#测试结果
3e-07
6
82.5235314
该算法缺陷:效率低下,因为重复计算太多
递归解法改进版:
解决重复计算的方法:用一个表将计算过的中间结果保存起来,下次计算前查表看是否计算过。
这个算法的中间结果就是部分找零的最优解,在递归调用过程中已经得到的最优解被记录下来。在递归调用之前,先查表看是否已有部分找零的最优解,若有,则直接返回最优解而不递归调用;若没有,才进行递归调用,直至结束。
改进python代码:
def recDC(coinvaluelist,change,knownresults):
mincoins=change
if change in coinvaluelist: #递归基本结束条件
knownresults[change]=1 #记录最优解
return 1
elif knownresults[change]>0:
return knownresults[change] #查表成功,直接用最优解
else:
for i in [c for c in coinvaluelist if c<=change]:
numcoins=1+recDC(coinvaluelist,change-i,knownresults)
if numcoins<mincoins:
mincoins=numcoins
knownresults[change]=mincoins #找到最优解,记录到表中
return mincoins
import time
print(time.clock())
print (recDC([1,5,10,25],63,[0]*64))
print(time.clock())
3e-07
6
0.0009077
测试结果:
计算时间大幅度缩短,结果秒回!