算法三

问题描述

假设在某国存在[1,x1,x2,x3,...,xn]多种货币,该国的自动贩卖机在找零时要遵循一个原则——“找零的总张数最少”。那么,该如何编写程序,帮助自动贩卖机自动找零呢?

问题分析

解决这一问题的最直接思路是穷举法。假设需要找零Y元,那么就通过所有的小于Y的货币,列举出找零的所有方案,进而比较哪个总张数最少。这种思路需要在计算中蕴含有大量的重复,时间复杂度极大。
类似问题的一个有效解法是使用动态规划的思想来处理。

求解找零所需要最少货币数

以面值为1,5,10,25的货币为例:

解决这一问题的关键在于,利用类似的等式,不断缩小问题的规模。当问题缩小为“需要多少张货币来找0元”时,问题的答案显然是0。
我们需要额外做的就是创建一个列表,用以保存比要计算的找零需求更小的需求。

# need_change 为需要找零的金额,
# currency_list 为该国货币的面值列表,
# num_list 为需要找零的最少货币数目, num_list的长度至少为(need_change+1)
def giveChange(need_change, currency_list, num_list):
    for change in range(need_change+1): #从0开始计算最少需要的货币数
        for currency in currency_list: #遍历每一种货币
            if (change-currency >= 0) and (num_list[change-currency]+1<num_list[change]): #计算最少货币需求数
                num_list[change] = num_list[change-currency] + 1
    return

def main():
    need_change = 63
    currency_list = [1,5,10,21,25]
    num_list = list(range(need_change+1)) #初始化num_list为0到need_change,共(need_change+1)个数
    giveChange(need_change, currency_list, num_list)
    print("%d 需要 %d 个货币来找零"%(need_change, num_list[need_change]))
if __name__ == "__main__":
    main()

运行结果为:

63 需要 3 个货币来找零

仅仅输出了正确的货币数目是不够的,我们还需要输出具体是哪些面值的货币。

自动找零问题的解决

如同常见的,最短路径的记录一样。为输出具体是需要找哪些面值的货币的零钱,我们需要再上一步骤的基础上记录下每步求解最小化使用的货币。
为此,我们需要在添加一个列表,用以记录这个数值。

# need_change 为需要找零的金额,
# currency_list 为该国货币的面值列表,
# num_list 为需要找零的最少货币数目, num_list的长度至少为(need_change+1)
# used_list 为需要找零的最少货币数目, 长度与num_list相同
def giveChange(need_change, currency_list, num_list, used_list):
    for change in range(need_change+1): #从0开始计算最少需要的货币数
        for currency in currency_list: #遍历每一种货币
            if (change-currency >= 0) and (num_list[change-currency]+1<=num_list[change]): #计算最少货币需求数
                num_list[change] = num_list[change-currency] + 1
                used_list[change] = currency #记录消耗的货币
    return

# 返回需要的货币
def showChange(need_change, used_list):
    give_list = []
    while need_change > 0:
        give_list.append(used_list[need_change])
        need_change -= used_list[need_change]
    give_list.sort() #排序
    return give_list

def main():
    need_change = 64 #需要找零的钱数
    currency_list = [1,5,10,21,25] # 该国的货币面值列表
    num_list = list(range(need_change+1)) #初始化num_list为0到need_change,共(need_change+1)个数
    used_list = list(range(need_change+1)) #初始化used_list为0到need_change,共(need_change+1)个数
    giveChange(need_change, currency_list, num_list, used_list)
    print("%d 需要 %d 个货币来找零"%(need_change, num_list[need_change]))
    give_list = showChange(need_change, used_list)
    print(give_list)

if __name__ == "__main__":
    main()

计算结果为:

64 需要 4 个货币来找零
[1, 21, 21, 21]
时间: 2024-10-14 05:58:23

算法三的相关文章

Dijkstra算法(三)之 Java详解

前面分别通过C和C++实现了迪杰斯特拉算法,本文介绍迪杰斯特拉算法的Java实现. 目录 1. 迪杰斯特拉算法介绍 2. 迪杰斯特拉算法图解 3. 迪杰斯特拉算法的代码说明 4. 迪杰斯特拉算法的源码 转载请注明出处:http://www.cnblogs.com/skywang12345/ 更多内容:数据结构与算法系列 目录 迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想

Kruskal算法(三)之 Java详解

前面分别通过C和C++实现了克鲁斯卡尔,本文介绍克鲁斯卡尔的Java实现. 目录 1. 最小生成树 2. 克鲁斯卡尔算法介绍 3. 克鲁斯卡尔算法图解 4. 克鲁斯卡尔算法分析 5. 克鲁斯卡尔算法的代码说明 6. 克鲁斯卡尔算法的源码 转载请注明出处:http://www.cnblogs.com/skywang12345/ 更多内容:数据结构与算法系列 目录 最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的

图解缓存淘汰算法三之FIFO

1.概念分析 FIFO(First In First Out),即先进先出.最先进入的数据,最先出来.一个很简单的算法.只要使用队列数据结构即可实现.那么FIFO淘汰算法基于的思想是"最近刚访问的,将来访问的可能性比较大".看了这三个算法,大家对淘汰的理解,我想一定深入了不少,基于一种对未来可能性的推断上. 2.原理分析 FIFO的淘汰过程与传送带的方式类似,最先放到传送带上的数据会最先被淘汰.如下图中的A. 3.优略分析 [命中率] 命中率较低,不推荐使用. [复杂度] 非常简单.

用OpenCV实现Photoshop算法(三): 曲线调整

http://blog.csdn.net/c80486/article/details/52499919 系列文章: 用OpenCV实现Photoshop算法(一): 图像旋转 用OpenCV实现Photoshop算法(二): 图像剪切 用OpenCV实现Photoshop算法(三): 曲线调整 用OpenCV实现Photoshop算法(四): 色阶调整 用OpenCV实现Photoshop算法(五): 亮度对比度调整 用OpenCV实现Photoshop算法(六): 变为黑白图像 用OpenC

搞定面试算法系列 —— 分治算法三步走

主要思想 分治算法,即分而治之:把一个复杂问题分成两个或更多的相同或相似子问题,直到最后子问题可以简单地直接求解,最后将子问题的解合并为原问题的解. 归并排序就是一个典型的分治算法. 三步走 和把大象塞进冰箱一样,分治算法只要遵循三个步骤即可:分解 -> 解决 -> 合并. 分解:分解原问题为结构相同的子问题(即寻找子问题) 解决:当分解到容易求解的边界后,进行递归求解 合并:将子问题的解合并成原问题的解 这么一说似乎还是有点抽象?那我们通过经典的排序算法归并排序来体验一下分治算法的核心思想.

算法三之堆排序

一.堆(Heap)定义 (1)n个关键字序列Kl,K2,-,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): k(i)<=k(2i)且k(i)<=k(2i+1)(1≤i≤ n/2), 当然,这是小根堆,大根堆则换成>=号. (2)k(i)相当于二叉树的非叶子结点,K(2i)则是左子节点,k(2i+1)是右子节点 若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均不大于(或不小于)其左右孩

(高效率排序算法三)堆排序

一.堆的介绍         动态效果图         堆有如下特点的二叉树: 1.他是完全的二叉树.也就是说,除了树的最后一层布需要时满的,其他的每一层从左到右都是满的.(如下图的完全二叉树跟不完全二叉树) 2.它常常用一个数组在实现.(如下图显示了堆它与数组之间的关系.堆在存储器中的表示是数组:堆只是概念上的表示.注意树是完全二叉树,并且所有的节点满足堆的条件) 3.堆中的每一个节点都满足堆的条件,也就是说每一个节点的值都大于或者等于这个节点的子节点的值(如上图) 二,堆的移除 1.只能移

Java数据结构和算法(三)——简单排序

单单有数据还不够,对于数据的展现,经常要按照一定的顺序进行排列,越高要求的排序越复杂,这篇只介绍三种大小的简单排序. 1)冒泡排序 模拟:有数组,1,4,2,5,7,3. (1)首先从1开始冒泡,1比4小,不冒,4大于2,冒上去,与2交换位置,4比5小,不冒,7比3大,冒,结果:1,2,4,5,3,7 (2)接下来从2开始,因为第一个元素冒过了,重复(1),结果:1,2,4,3,5,7 (3)从第三位4开始,结果1,2,3,4,5,7 (4)虽然看起来已经排好序,但是还是要继续冒,接下来就是从第

漫谈二叉搜索树的基本算法(三种思路实现查询操作)

  前面我们说了二叉树前序中序后序遍历的递归非递归算法的实现,下面我们再来说说二叉搜索树~   二叉排序树分为静态查找(find)和动态查找(insert.delete) 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足下列性质: 1.非空左子树的所有键值小于其根结点的键值. 2.非空右子树的所有键值大于其根结点的键值 3.左右子树都是二叉搜索树!! 2.以上是二叉搜索树(也叫二叉排序树)的一些基本操作,此处我们先说一下二叉树的结点定义·· 代码中判断当前结点位置情况的辅助方法以及简单的 ge

【翻译】利用加速度求解位置的算法——三轴传感器

摘要 此文档描述并使用MMA7260QT三轴加速计和低功耗的9S08QG8八位单片机实现求解位置的算法 . 在今天先进的电子市场,有不少增加了许多特性和智能的多功能的产品.定位和游戏只是得益于获取到的位置信息的一部分市场.一个获取这种信息的可选方案是通过使用惯性传感器.从这些传感器中取得的信号需要进行一些处理,因为在加速度和位置之间没有一种直接转换. 为了获得位置,需要对加速度进行二次积分.本文介绍一种简单的算法实现加速度的二重积分.为了获取加速度的二重积分,一个简单的积分要进行两次,因为这样也