本章节主要结合动态规划的实例代码进行讲解,使用python语言。
题目一: 选出的数字不能相邻,且使得选出的数字总和最大。
1.1 问题原理介绍
比如:可以选择1和9,结果为10。
但是如果选择4和9,结果为13,则结果为最优的。
并且选择的时候不一定非要选择两个,也可以选择其它方案,如下图所示
但是选出的方法结果也不会超过13,所以该方案并非最优。
1.2 代码与实例讲解
上节我们采用的是选与不选的解决方法来解决动态规划问题,对于该实例同样适用。
实例内容解析:OPT(6)为求解到下标为6的位置的最佳方案是什么?
分析OPT(6):(+)代表选择,(-)代表不选。
当然这里面有很多的重叠子问题:OPT(3)、OPT(4)
递归方程表示上述过程:
程序代码:
In [6]:
arr=[1,2,4,1,7,8,3]
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)
rec_opt(arr,6)
Out[6]:
15
存在的问题:上述代码存在重叠子问题,运算速度会很慢,时间复杂度会达到,采用非递归方法:
import numpy as np
arr=[1,2,4,1,7,8,3]
#非递归方法
def dp_opt(arr):
opt=np.zeros(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[len(arr)-1]
dp_opt(arr)
output:
15.0
题目二:从一个数组中选出一堆数字,使得这些数字的和等于给定的数字9,查找是否存在这样的方案?如果存在这样的方案,则打印True,否则False。
假设:所有的数字都是正整数
思路与上题一致。
subset(i,s)考虑第i个数字选不选,s为要求的数字。
只要左右两边的任何一个方案成立,那么就时True。中间用or连接。
出口设计:
(1)在处理到一半的时候s已经变为0。比如当我进行到arr[2]时,后面的已经能够得到我想要的数字,则前面的已经没有必要进行计算。直接输出True。
(2)如果i=0,arr[0]=s时才能返回True。
(3)如果arr[i]>s,就只考虑不选arr[i]这个数字的情况。
递归过程:
程序代码:
#三个出口条件,采用递归方法
aar=[3,34,4,12,5,2]
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
print(rec_subset(arr,len(arr)-1,9))
print(rec_subset(arr,len(arr)-1,10))
print(rec_subset(arr,len(arr)-1,11))
print(rec_subset(arr,len(arr)-1,12))
output:
True
True
True
True
采用非递归的形式:
思路分析:
程序代码:
#采用非递归方法,使用二维数组保存中间过程
#三个出口条件,采用递归方法
import numpy as np
aar=[3,34,4,12,5,2]
def dp_subset(arr,S):
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]
print(dp_subset(arr,9))
print(dp_subset(arr,10))
print(dp_subset(arr,11))
print(dp_subset(arr,12))
output:
True
True
True
False