重叠子问题
引入:
斐波那契数列
递归时间复杂度太高,考虑把已经算出的结果保存起来,减少重复工作
选与不选:
本题要求在下图中找到能够连接的任务,要使之不重叠并能使各任务红字相加达到最大。
对每个任务i,当这个任务被选择时,前面必然有部分不重叠,部分重叠,将不重叠部分相加,比如OPT(8) = 4+OPT(5)
当这个任务不被选择时,
例:
选出一串数字中一些数字,使得数字不相邻,且数字和最大
1241783
import numpy as np
arr = [1,2,4,1,7,8,3]
def rec_opt(a, i): #递归
if i == 0:
return a[i]
elif i == 1:
return max(a[0], a[1])
else :
A = rec_opt(a, i-1)
B = rec_opt(a, i-2)+a[i]
return max(A, B)
rec_opt(arr, 6)
def dp_opt(a, i):
opt = np.zeros(len(a))
opt[0] = a[0]
opt[1] = max(a[0], a[1])
for i in range(2, len(a)):
opt[i] = max(opt[i-1], opt[i-2]+a[i])
return opt[len(a)-1]
dp_opt(arr, 6)
在一串数字中选择几个数字使得相加之和等于给定数字,存在则返回true,不存在则返回false
例:
3,34,4,12,5,2
s = 9
arr = [3, 34, 4, 12, 5]
def rec_subset(a, i, s):
if s == 0:
return True
elif i == 0:
return a[i] == 0
elif a[i] > s:
return rec_subset(a, i-1, s)
else:
return rec_subset(a, i-1, s-a[i]) or rec_subset(a, i-1, s)
rec_subset(arr, 4, 12)
import numpy as np
def dp_subset(a, s):
subset = np.zeros((len(a), s+1), dtype = bool)
subset[:, 0] = True
subset[0, :] = False
subset[0, a[0]] = False
for i in range(1, len(a)):
for j in range(1, s+1):
if a[i] > j:
subset[i][j] = subset[i-1][j]
else:
A = subset[i-1][j]
B = subset[i-1][j-a[i]]
subset[i, j] = A or B
r, c = subset.shape
return subset[r-1, c-1]
print dp_subset(arr, 9)
print dp_subset(arr, 13)
subset[ i, s]代表当a[i]之前是否能凑出s
https://www.bilibili.com/video/BV12W411v7rd/?spm_id_from=333.788.videocard.0