Example of efficiently computing Fibonacci numbers using a cache to implement a dynamic programming technique:

@lru_cache(maxsize=None)

def fib(n):

if n < 2:

return n

return fib(n-1) + fib(n-2)

>>> [fib(n) for n in range(16)]

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

>>> fib.cache_info()

CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

New in version 3.2.

Changed in version 3.3: Added the typed option.

 

https://en.wikipedia.org/wiki/Dynamic_programming

https://zh.wikipedia.org/wiki/动态规划

动态规划(英语:Dynamic programming,简称DP)是一种在​​数学​​、​​管理科学​​、​​计算机科学​​、​​经济学​​和​​生物信息学​​中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

动态规划常常适用于有重叠子问题​[1]​和​​最优子结构​​性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。

通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其​​记忆化​​存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈​​指数增长​​时特别有用。

 

动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存​​递归​​时的结果,因而不会在解决同样的问题时花费时间。

动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

 

  1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
  2. 无后效性。即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。
  3. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

背包问题

  • 最长公共子序列
  • Floyd-Warshall算法
  • Viterbi算法

 

实验代码



import time


def fib(**kwargs):
n = kwargs['n']
if n < 2:
return n
return fib(n=(n - 1)) + fib(n=(n - 2))


def now():
return time.time()


def runtime(f, **kwargs):
s = now()
f(**kwargs)
e = now()
return e - s


import functools


@functools.lru_cache(maxsize=None)
def fib_cache(**kwargs):
n = kwargs['n']
if n < 2:
return n
return fib_cache(n=(n - 1)) + fib_cache(n=(n - 2))


if __name__ == '__main__':
N = [2, 4, 8, 16, 32, 64]
for i in N:
print(i, ':', fib(n=i), ',', fib_cache(n=i), runtime(fib, n=i), ',', runtime(fib_cache, n=i))


  

2 : 1 , 1 0.0 , 0.0

4 : 3 , 3 0.0 , 0.0

8 : 21 , 21 0.0 , 0.0 1

6 : 987 , 987 0.0009951591491699219 , 0.0

32 : 2178309 , 2178309 1.3061189651489258 , 0.0