动态规划 dynamic programming
分治方法将问题划分为互不相交的子问题,递归地求解子问题,再将它们组合起来求出原问题的解。而动态规划则应用与子问题重叠的情况,即不同的子问题具有公共的子子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。动态规划算法对每个子子问题只求解一次,将其解保存在一个表格中,从而无需反复计算。
动态规划算法常规步骤:
1. 刻画一个最优解的结构特征
2. 递归地定义最优解的值
3. 计算最优解的值,通常采用自底向上的方法
4. 利用计算出的信息构造一个最优解
步骤3可以得到最优解的值,如果需求步骤4得到最优解,需要在执行3的过程中维护一些额外信息。
钢条切割问题
自顶向下:
常规遍历解法,循环1-n,剩余部分递归求解,额外引入数组r[n]=q,
用于记录计算过的长度为n的最大收益。
自底向上:
如果i<j,则规模为i的子问题“更小”,因此,过程依次求解规模为j=0,1,…,n的子问题。
def dp11(n):
r = dict()
r[0] = 0
for i in range(1,n+1):
q = -1
for j in range(1,i+1):
q = max(q,p[j]+r[i-j])
#从最小子问题开始求解r,key=i-j逐渐增加,不会抛出异常
r[i] = q
return r[n]
最长公共子序列问题(不要求在原序列中连续出现)
序列X,Y,长度m,n,子序列Xi,Yj,长度i,j
问题简化为
c[i,j] = 0 i= 0 或j = 0
c[i-1,j-1] + 1 i,j > 0 且 xi = yi
max(c[i,j-1],c[i-1,j]) i,j > 0 且 xi != yi
c[i,j]是保存了对应两个序列LCS长度的二维列表,时间复杂度Θ(mn)