对于动态规划,一直感觉会了,但又不怎么会,难点的题也做不到自己完成,今天再总结一下:
首先动态规划到底是干啥的?
现在想来,应该是用数组记录递归中的结果【第一次接触动态规划就是斐波那契了吧
然后动态规划要做到每次选最佳方案【OPT】
怎么得到这个OPT呢?
对于下一个数,我们可以选择、也可以不选,如果选择,那么OPT就是前一个不冲突的OPT+这个数;如果不选,那么OPT不会变,还是之前的OPT。这里举个栗子:
对一数组{1,2,4,1,7,8,3},选择不相邻的数,使其相加所得和最大
计算OPT(i):
OPT(0)=arr[0]
OPT(1)=max(arr[0],arr[1])
之后的最佳方案:
选择第i个,那么OPT(i)=OPT(i-2)+arr[i]
不选择第i个,OPT(i)=OPT(i-1)
注:通常前两个值是特殊值,不过特殊情况特殊考虑
递归写法:
arr=[1,2,4,1,7,8,3]
def opt(arr,i):
if i==0:
return arr[0]
elif i==1:
return max(arr[0],arr[1])
else:
A=opt(arr,i-2)+arr[i]
B=opt(arr,i-1)
return max(A,B)
动规写法:
将中间结果存在数组opt中
import numpy as np#创建数组用的包
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]
对一数组{1,2,4,1,7,8,3},判断是否有两数相加为特定数12?
剪枝,从后往前选或不选
sub(arr[6],12),【i=6,s=12】表示arr[6]前相加可以为12就行,对于arr[6]选或者不选
选为:sub(arr[i-1],s-arr[i])------>sub(arr[5],9)
不选为:sub(arr[i-1],s)------>sub(arr[5],12)
这两个有一个满足返回true
特殊值:
- 当第二项参数为0,说明已经符合题意,返回true
- 当只剩下一个数字arr[0]时,判断arr[0]是否等于此时的第二项:
相等则返回true- 当arr[i]大于第二项,不用考虑选的情况,因为不能加出个负数
递归实现:
def sub(arr,i,s):
if s==0:
return True
elif i==0:
return arr[0]==s
elif arr[i]>s:
return sub(arr,i-1,s)
else:
A=sub(arr,i-1,s)
B=sub(arr,i-1,s-arr[i])
return A or B
动规实现:
用二维数组存储:[arr[i],s]
import numpy as np
def dp_sub(arr,su):
#二维数组设计
sub=zeros((len(arr),s+1),dtype=bool)#含s=0
sub[:,0]=True#每一行第0列【s==0】为True
sub[0,:]=False#第0行除arr[0]==s外,都为False
sub[0,arr[0]]=True
for i in range(1,len(arr)):
for s in range(1,su+1):
if arr[i]>s:
sub[i,s]=sub[i-1,s]
else:
A=sub[i-1,s]
B=sub[i-1,s-arr[i]]
sub[i,s]=A or B
r,c=sub.shape#获得行数、列数
return sub[r-1,c-1]
关键点:
找出口【特殊值】
分析选或不选的公式