动态规划综述
- 可分为多个相关子问题,子问题的解可以被重复使用(下方例子中是F数组与value数组来保留子问题解的),这也是相比于递归暴力求解效率提高的关键,下方前两个例子会简单比较效率,第二个例子由于数据不具代表性,所以有所差异
- 动态规划的关键就是如何根据条件从上一个子问题的最优解到该现状的途径(写出递推关系)
- 然后该途径会有很多种再根据问题通过min或max求得哎现状的最优解,该现状当然也又有可能出现在之后现状的子问题当中
- 写出初始条件
- (之前自己理解的误区)在理解中不要仅仅注意到递推关系,比如背包问题中之前理解错了是总是感觉包括第i件物品的组合肯定肯定比不包括第i件物品的组合的总价值大,这种理解的错法在于没有真正理解到动态规划的自下而上,而仅仅看到了递推关系,实际上这里F(i ,j),变的不仅仅是i,还有j,相当于你不包括第i件物品,那么你就有更多的空间去选择其他的,总之就是包含第i件与不包含第i件的前一子组合的子组合是不同的。(之前初次接触的背包问题的误区,这次系统看了下动态规划,欢迎交流)
- 上面看不懂?直接看代码!
参考书籍:《算法分析与设计》
参考博客: https://blog.csdn.net/qq_34178562/article/details/79959380
github(jupyter源码): https://github.com/Justin3go/BasicComputerNotes/tree/main/算法分析与设计
币值最大化问题
问题描述:给定一排硬币,这些整数不一定两两相同。使得在其原始位置互不相邻的条件下,所选硬币金额最大。
算法思想:
- 包括最后一枚的:c_n + F(n-2)
- 不包括最后一枚的:F(n-1)
动态规划实现
def CoinRow1(coins):
F = [0]
F.append(coins[0])
for i in range(1, len(coins)):
F.append(max(coins[i] + F[i-1], F[i]))
return F[len(coins)]
test_coin = [5, 1, 2, 10, 6, 2]
CoinRow1(test_coin)
17
递归实现
def CoinRow2(coins, i):
if i == 0:
return 0
if i == 1:
return coins[0]
return max((coins[i] + CoinRow2(coins, i - 2)), CoinRow2(coins, i - 1))
test_coin = [5, 1, 2, 10, 6, 2]
CoinRow2(test_coin, len(test_coin)-1)
17
效率比较
import matplotlib.pyplot as plt
import numpy as np
import time
cost_time_log1 = []
cost_time_log2 = []
for i in range(1, 6):
print(
"**********************************第%s数据规模********************************"
% i)
# 数据生成
test_coins = list(np.random.randint(0, 1000, i * 6))
t1 = time.time()
print("CoinRow1", CoinRow1(test_coins))
t2 = time.time()