python函数找钱_找钱问题–动态规划一例

用无限多的面值为 S = {S1, S2,  …, Sm} 的分币,表示一个特定的分值n,有多少种方法?这个就是找钱问题 (Coin Change Problem)。

比如,用 1美分 和 5 美分,表示7美分,有2种方法,第一种是1个5美分,2个1美分;第二种是7个1美分。

因为顺序对结果没有影响,即“1个5美分,2个1美分”和“2个1美分,1个5美分”是一样的,我们限定 S1 < S2 < … < Sm。用递归的方法,解法的数量 C(n, m),可以分成2类:

一类是表示方法里不需要 Sm的,另一类是表示方法里需要Sm的。如上面的例子,一类表示是需要5美分,另一类不需要。

于是,递归公式如下:

C(n, m) = C(n, m-1) + C(n-Sm, m)

Python代码:def count1(n,m):

global numCalls

numCalls += 1

global S

if n == 0:

return 1

if n < 0:

return 0

if m == 1:

return 1

return count1(n, m-1) + count1(n-S[m-1],m)

S = (1,5,10,25)

numCalls = 0

print count1(100,len(S))

print numCalls

count1()函数的运行结果是242,即用 1美分,5美分,10美分和25美分表示100美分有242种方法。

numCalls是13927,说明count1()函数被调用了13927次。这是因为我们重复计算了很多相同的中间结果。

动态规划应用于以下情况:子问题的最优解也是整体问题的最优解,同时子问题有重叠。那么就可以把子问题的解保存起来,只需要计算一次就可以。

于是:def count(n,m):

global numCalls

numCalls += 1

global S

global memo

try:

return memo[(n,m)]

except KeyError:

if n == 0:

memo[(n,m)] = 1

return 1

if n < 0:

memo[(n,m)] = 0

return 0

if m == 1:

memo[(n,m)] = 1

return 1

memo[(n,m)] = count(n, m-1) + count(n-S[m-1],m)

return memo[(n,m)]

S = (1,5,10,25)

memo = {}

numCalls = 0

print count(100,len(S))

print numCalls

count()函数和count1()函数的唯一区别就是count()函数用一个字典 memo 记录了子问题的解。因此运行结果是一样的,都是242;

但是numCalls是285,说明count()函数仅被调用了285次。这就是动态规划保存子问题的解的神奇结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值