找零问题——贪心

1.贪心算法简介

        贪心算法又称贪婪算法,在求解一个问题时总是做出在当前看来是最好的选择。

        贪心算法的核心是贪心策略的选择,必须确保选择的贪心策略具备无后效性,即某个状态以前的过程不会影响以后的状态,只是与当前状态有关。

        当使用贪心算法去解决某一问题时,会从问题的某一初始解出发逐渐逼近给定的目标解,这样可以尽快求出更好的解。当达到算法中的某一步不能再继续前进时,就停止运行并给出一个近似解。

由贪心算法的特点和解体思路可以看出,贪心算法存在以下3个问题:

(1)不能保证最后的解是最优的。

(2)不能用来求最大或最小解问题。

(3)只能求满足某些约束条件的可行解的范围。

贪心算法与动态规划不同,贪心算法对每个子问题的解决方案都做出选择,不能回退。动态规划则会根据以前的选择结果对当前进行选择,有回退功能。动态规划主要运用于二维或三维问题,而贪心算法一般是一维问题。

2.贪心算法基本思路

从问题的某一初始解出发,然后按照顺序依次进行,根据某个决策确保每一步都能获得局部最优解。在每一步只考虑一个数据,这个被选取的数据应该是局部最优解的条件。如果下一个数据和局部最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据都枚举完,或者不能再添加算法停止。

3.找零问题

        假设有1分、2分、5分、1角、2角、5角、1元这几种类型的硬币。在超市结账时,如果需要找零钱,收银员希望将最少的硬币数找给顾客,那么,给定需要找的零钱数目,如何求得最少的硬币数呢?

        假设要找的金额是n,则用n除以最大面额零钱的面值,取整就是所找的最大面额零钱的个数,更新n值,重复上述操作直到最小面额结束。

        实现代码如下

from decimal import *
def main():
    d = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0]
    d_num = []
    """-------------------------------------------------------------------------"""
    tmp = input("请输入每种零钱的数量(7种面额,输入0使用默认值):").split()
    if len(tmp) == 1 and tmp[0] == "0":
        d_num = [15 for i in range(len(d))]
    else:
        for i in range(len(d)):
            d_num.append(float(tmp[i]))
    """-------------------------------------------------------------------------"""  
    """计算收银员有多少零钱总额"""
    sum_d = 0
    for i in range(len(d_num)):
        sum_d += d[i] * d_num[i]
    me_d = float(input("请输入要找的零钱:"))
    if me_d > sum_d:
        print("收银员找不出这么多钱,数据有错!")
        return 0
    """-------------------------------------------------------------------------"""
    """从面额最大的元素开始遍历"""
    i = len(d) - 1
    count = 0
    while i >= 0:
        if me_d >= d[i]:
            n = int(me_d / d[i])
            if n >= d_num[i]:
                n = d_num[i]
            count += n
            dec = float(n) * d[i]
            """令me_d动态改变(贪心关键),使用decimal提高运算精度"""
            me_d = float(Decimal(str(me_d)) - Decimal(str(dec)))
            print("用了%d个%.2f元的硬币" % (n, d[i]))
        i -= 1
    print("总共用了%d枚硬币" % count)

if __name__ == "__main__":
    main()

输出结果:

请输入每种零钱的数量(7种面额,输入0使用默认值):0
请输入要找的零钱:0.95
用了1个0.50元的硬币
用了2个0.20元的硬币
用了1个0.05元的硬币
总共用了4枚硬币

4.代码调试发现的问题以及解决办法:

 先看一个例子:

>>> a = 0.95 - 0.50
>>> print(a)
0.44999999999999996

问题:一开始,我的代码中没有用到decimal这个模块,就是普通的两数相减,导致结果不符合预期 ,我就Debug一下,发现float类型的数据相减时跟我们平常手算的结果完全不一样,然后就上网搜索,原因是计算机在进行浮点数计算时是用二进制来近似代替浮点数进行计算的,所以出来的结果也是近似值运算后的结果。这是计算机的问题,不是语言问题。

解决办法:通过搜索,我了解到python中的Decimal()方法可以让浮点运算结果和人平时运算的结果一样,实质上是通过加长长度提高精度再进行运算。

想了解更多关于decimal模块的知识,可以去python的官网看看:

python_decimal

你可能感兴趣的:(算法,贪心算法,python)