问题1:有1,3,5三种硬币,输入待找币数,输出最少用币。(如输入15)
思路:可以把15划分为14+1,12+3,10+5三种情况来看,这样我们就把问题给缩小了,对14,12,10同理。
分析;设f(x)为找x元所需的最少硬币数,显然
f(0)=0,
f(1)=1,
f(2)=f(1)+1=f(2-1)+1,
f(3)=min{f(2)+1,f(0)+1}=min{f(3-1)+1,f(3-3)+1}
f(4)=min{f(3)+1,f(1)+1}=min{f(4-1)+1,f(4-3)+1}
f(5)=min{f(4)+1,f(2)+1,f(0)+1}=min{f(5-1)+1,f(5-3)+1,f(5-5)+1}
...
f(15)=min{f(15-1)+1,f(15-3)+1,f(15-5)+1}
...
f(x)=min{f(x-1)+1,f(x-3)+1,f(x-5)+1}
到这里,可以看出问题的关键了,就是min{f(x-1)+1,f(x-3)+1,f(x-5)+1},这条就是状态转移方程,将一个大问题不断变成小的子问题。
代码实现如下:
#输入x为找零数,coin为可用硬币
x = input()
x = int(x)
COIN = [1,3,5]
#创建列表以保存所需硬币数,+1是想直接从1开始,默认是0,长度会不够
f = [float('inf')]*(x+1)
f[0] = 0
#理财开始~
for i in range(f.__len__()): #从f(0)开始计算
for j in COIN: #尝试各种硬币
if i>=j: #避免硬币过大
if f[i-j]+1<f[i]: #min{}操作
f[i]=f[i-j]+1
print(f[x])
下面给出带找零方案的代码:
#输入x为找零数,coin为可用硬币
x = input()
x = int(x)
COIN = [1,3,5]
#创建列表以保存所需硬币数,+1是想直接从1开始,默认是0,长度会不够
# f = [[float('inf'),0]]*(x+1)
f=[]
for i in range(x+1):
f.append([float('inf'),0])
f[0][0] = 0
#理财开始~
for i in range(f.__len__()): #从f(0)开始计算
for j in COIN: #尝试各种硬币
if i>=j: #避免硬币过大
if f[i-j][0]+1<f[i][0]: #min{}操作
f[i][0]=f[i-j][0]+1
f[i][1]=j
print('total: '+str(f[x][0]))
while x != 0:
print(str(x) + '----' +str(f[x][1]))
x-=f[x][1]
初学python,列表的初始化可能写的不好。
小结
显然,这是一个动态规划的典型例子。阶段性地做出当前最优决策,这里就涉及到了一个最优子结构问题,如果没有最优子结构的问题是不可以用动态规划来解决的。