动态规划解决硬币找零问题

题目描述:给定不同面额的硬币 coins 和一个需要找零的金额 n。编写一个函数来计算可以凑成金额n所需的最少的硬币个数。并求出所需硬币的所有面额并输出。(硬币可重复多次使用)

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式 。

解题思路:从最小的0开始:当i=0,即需要0个硬币来凑够0元。用nums[i]=j来表示凑够i元最少需要j个硬币。当i=1时,只有面值为1元的硬币可用。然后再凑够i-1=1-1=0元即可。所以,nums[1]=nums[1-1]+1=nums[0]+1=0+1=1。当i=2时,仍然只有面值为1元的硬币可用。然后再凑够i-1=2-1=1元即可。所以,nums[2]=nums[2-1]+1=nums[1]+1=1+1=2。当i=3时,有两种硬币可用,也有两种方式:第一种:nums[3]=nums[3-1]+1=nums[2]+1=nums[2]+1=3。这种是使用面值为1的硬币在nums[2]的基础上进行更新nums[3]。第二种:nums[3]=nums[3-3]+1=nums[0]+1=0+1=1。这种是使用面值为3的硬币在nums[0]的基础上进行更新nums[3]。由于要用最少的硬币数量来凑够3元。所以,选择第二种方式。具体是这样得到的:nums[3]=min{nums[3-1]+1, nums[3-3]+1}。

抽象一下,可得到如下公式:

 

                                                                                                     

下面附上python代码:

import sys


def get_nums(n, coins):
    nums = [sys.maxsize] * (n + 1)  # 产生一个长度为N+1,元素为sys.maxsize的列表,用来存放所需最少的硬币数量
    result = [0] * (n + 1)  # 产生一个长度为N+1,元素为0的列表,用来存放第i个数据最少硬币的数量更新时是由前面哪一个数据进行更新来的
    nums[0] = 0
    # nums[1] = 1

    for i in range(1, n + 1):
        for j in coins:
            if j <= i and nums[i - j] + 1 < nums[i]:  # 更新条件
                nums[i] = nums[i - j] + 1
                result[i] = i - j  # 更新来源表,即第i个数据用来存放所需最少的硬币数量最终是根据第result[i]个数据进行更新的
    print(nums[n], result)
    return result


# 输出组成n所需要的所有最少硬币的面额
def get_coins(result, n):
    ans = []
    while 1:
        if result[n] != 0:
            ans.append(n - result[n])
            n = result[n]
        else:
            ans.append(n - result[n])
            break
    return ans


n = input('请输入一个整数')

print(get_coins(get_nums(n, [1]), n))
print(get_coins(get_nums(n, [1, 5]), n))
print(get_coins(get_nums(n, [1, 5, 8]), n))

print('-----------------------------------')

print(get_coins(get_nums(n, [1]), n))
print(get_coins(get_nums(n, [1, 2]), n))
print(get_coins(get_nums(n, [1, 2, 5]), n))

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值