动态规划问题及例题代码实现
动态规划Dynamic Programming
1.动态规划理论
1.1动态规划基本思想
注意:斐波那契递归求解的时间复杂度为O(2n)。
子问题不独立适合动态规划算法设计。
分治:将原问题划分为互不相交的子问题,递归求解子问题,再将它们的解组合起来。
动态规划:子问题重叠的情况,不同的子问题具有公共的子子问题
利用动态规划需要满足:
问题中的状态满足最优性原理。 =》最优子结构
问题中的状态必须满足无后效性。 =》以前出现的状态和以前状态的变化过程不会影响将来的变化
1.2动态规划的基本步骤
2 举例
1.任务调度安排
2. 不相邻数字和最大
求一堆不相邻数字和最大,没有要求选两个,可以选多个。
OPT(n)指的是数据到下标为n的数字选取的最好的方案。
代码如下:
#递归方程实现
def rec_opt(arr, i):
if i == 0:
return arr[0]
elif i == 1:
return max(arr[0], arr[1])
else:
A = rec_opt(arr, i - 2) + arr[i]#选择当前值
B = rec_opt(arr, i - 1)#不选当前值
return max(A, B)
#非递归实现:dp动态规划
def dp_opt(arr):
opt = [0 for i in range(len(arr))]
opt[0] = arr[0]
opt[1] = max(arr[0], arr[1])
for i in range(2,len(arr)):
A = opt[i-2] + arr[i]
B = opt[i-1]
opt[i] = max(A,B)
return opt[-1]
arr1 = [4, 1, 1, 9, 1]
arr2 = [1, 2, 4, 1, 7, 8, 3]
print(rec_opt(arr1, len(arr1)-1))#13
print(dp_opt(arr1))#13
print(rec_opt(arr2, len(arr2)-1))#15
print(dp_opt(arr2))#15
3.给出一个数字和一个数组,判断是否数组中存在一些数的和为给出的数字
#递归实现
def rec_subset(arr, i, s):
if s == 0:
return True
elif i == 0:
return arr[0] == s
elif arr[i] > s:
return rec_subset(arr, i-1, s)
else:
A = rec_subset(arr, i-1, s-arr[i])
B = rec_subset(arr, i-1, s)
return A or B
arr = [3, 34, 4, 12, 5, 2]
print(rec_subset(arr, len(arr)-1, 9))#True
print(rec_subset(arr, len(arr)-1, 10))#True
print(rec_subset(arr, len(arr)-1, 13))#False
#非递归实现:dq动态规划
def dp_subset(arr, S):
import numpy as np
subset = np.zeros((len(arr), S+1), dtype=bool)
subset[:, 0] = True
subset[0, :] = False
subset[0, arr[0]] = True
for i in range(1, len(arr)):
for s in range(1, S+1):
if arr[i] > s:
subset[i, s] = subset[i-1, s]
else:
A = subset[i-1, s-arr[i]]
B = subset[i-1, s]
subset[i, s] = A or B
r, c = subset.shape
return subset[r-1, c-1]
arr = [3, 34, 4, 12, 5, 2]
print(dp_subset(arr, 9))#True
print(dp_subset(arr, 10))#True
print(dp_subset(arr, 13))#False