zoukankan      html  css  js  c++  java
  • python 算法 day5

    动态规划

    动态规划是用来求最优解问题的解决策略之一

    一个最典型例子 :用最少的硬币找零

    比如:一美元购买37美分商品,用来找零的硬币最小数量是多少(一般有1,5,10和25美分的硬币)

    首先我们使用最大面值的硬币(25美分),也是尽可能多的使用,接着再使用下一个面值最大的这种方法被称为贪心算法

    但如果有21美元时,贪心算法依然会首先选择25美分的,答案也仍然没有变化,而最优解是三个21美分的硬币

    我们可以根据递归,首先根据一美分去找,如果价值不匹配,我们就再加上一美分减去1美分找零总数的最小的整数值

    一个低效的方法

    def reticon(coinValueList , change):
        mincoin = change
        if change in coinValueList:
            return 1
        else:
            for i in [c for c in coinValueList if c<=change]:
                print(i)
                numcoin = 1 + reticon(coinValueList,change-i)
                if numcoin < mincoin:
                    mincoin = numcoin
        return mincoin
    
    
    print(reticon([1,5,10,25],63))

    图中每一个点对应一个retcion调用,主要问题我们做了大量重复性计算 列如:15美分的找零最优解至少三次1、5、10,每一次计算都需要调用52次函数

    减少工作量的关键在于记住一些出现过的结果,这样就能避免重复计算我们已经知道的结果

    一个简单的解决方法:

    我们将所找到的给硬币找零的最小数目储存在一个表中,然后计算最小值之前,可以先查看表中结果是否已知,如果有了,就可以直接调用,而不是重复计算。

    def reticon(coinValueList , change,knowresult):
        mincoin = change
        if change in coinValueList:
            knowresult[change]=1
            print(type(knowresult))
            return 1
        elif knowresult[change]>0:
            return knowresult[change]
        else:
            for i in [c for c in coinValueList if c<=change]:
    
                numcoin = 1 + reticon(coinValueList,change-i,knowresult)
                if numcoin < mincoin:
                    mincoin = numcoin
                    knowresult[change] = mincoin
        return mincoin
    
    
    print(reticon([1,5,10,25],63,[0]*64))  

    上述算法只是使用一种叫做“函数值缓存”来改善性能,真正的动态规划会采用更系统的方法去解决问题,把已经知道的最好的路径存起来,下次遇到可以直接用。动态规划的解决方法是从为第一分找零开始的最优解逐步加上去的,直到我们需要的找零数,这就保证了算法在每一步过程中,我们已经知道了兑换更小数值零钱所需硬币数量的最小值。

    1 2 3 4 5 6 7 8 9 10
    1                  
    1 2                
    1 2 3              
    1 2 3 4            
    1 2 3 4 1          
    1 2 3 4 1 2 3 4 5 1

    一个新的算法

    def dpMake(coinValueList,change,minCoins):
        for cents in range(change+1):
            coinCount = cents
            for j in [c for c in coinValueList if c<=cents]:
                if minCoins[cents-j] + 1 <coinCount:
                    coinCount = minCoins[cents-j] + 1
            minCoins[cents] = coinCount
        return minCoins[change]

    dpmake有三个参数:一个有效面值的列表  我们想要兑换的硬币数值   一个包含所有部分找零最优解的列表

    当程序运行时 mincoins会包含从0到所需兑换数值中每一个数值对应的最优解。

  • 相关阅读:
    java栈的最大深度?
    String hashCode 方法为什么选择数字31作为乘子
    LinkedList 源码分析(JDK 1.8)
    ArrayList 源码分析
    LinkedHashMap 源码详细分析(JDK1.8)
    Java并发基础:了解无锁CAS就从源码分析
    IntelliJ IDEA(2018)安装详解
    HashMap 源码详细分析(JDK1.8)
    Java原子类实现原理分析
    谈谈Java中的volatile
  • 原文地址:https://www.cnblogs.com/suizhixxie/p/10397322.html
Copyright © 2011-2022 走看看