《算法设计与分析》学习笔记之一:动态规划

《算法设计与分析》学习笔记之一:动态规划

动态规划(dynamic programming)

用于求解最优化问题(求目标函数 f(x) 在约束条件 x∈D 下的最小值或最大值的问题),即找到可行解中的一个最优解(最小值或最大值,an optional solution)。

与分治法的区别:分治应用于互不相交的子问题递归求解,动态规划应用于子问题重叠的情况;子问题重叠时,分治会反复求解重叠的子问题,但动态规划对每个子子问题只求解一次。

钢条切割问题

给定 n 英寸的钢条和价格表 P ,求使销售收益 rn 最大的切割方案。

现在设 rn 是最优切割的收益,考虑存在一次切割在位置 i ,则有:rn = ri + rn-i 。即有 rn = max 1≤j≤n { rj + rn-j , pn } 。

这体现了最优子结构性:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。

问题还能够简化:我们切成两段后只切割右侧 n - i 的部分,不再切割左侧的 i 。即将 “可能的一次切割的位置” 简化为 “最左侧切割的位置”,则有 rn = max 1≤j≤n { pj + rn-j }

如果我们用类似分治的简单自顶向下算法:

// Algorithm 1
CUT-ROD(p,n)
if n == 0
	q = 0
else q = -∞
	for i = 1 to n
		q = max(q, p[i]+CUT-ROD(p,n-i))
return q

则递归调用树如图15-3。若 T(n) 表示函数参数为 n 时的调用次数,等于递归调用树中根为 n 的子树中的结点总数,即

\[T(n) = 1 + \sum\limits_{j = 0}^{n - 1} {T(j)} \]

该递归调用树共有 2n 个结点(即 T(n) = 2n ),其中 2n-1 个叶子结点。(易证)

接下来使用两种动态规划的实现方法,它们是等价的,且均具有相同的渐进运行时间 Θ(n2) 。

带备忘的自顶向下法(top-down with memorization)

仍按自然递归编写过程,但保存每个子问题的解,若保存过则计算式直接返回此解(“带备忘的”,memorized)。

// Algorithm 2
MEMORIZED-CUT-ROD(p,n)
let r[0...n] be a new array
for i = 0 to n
	r[i] = -∞
return MEMORIZED-CUT-ROD-AUX(p,n,r)		// 此步建立了一个新数组,单独成为函数的原因是递归调用时不用再建立此数组

MEMORIZED-CUT-ROD-AUX(p,n,r)
	if r[n] ≥ 0
		return r[n]						// 在 Algorithm 1 前加一个直接输出的判断
	if n == 0 
		q = 0
	else  q = -∞
		for i = 1 to n
			q = max(q, p[i]+MEMORIZED-CUT-ROD-AUX(p,n-i,r))
	r[n] = q							// 在 Algorithm 1 后加上保存已经求出的解的过程
	return q

自底向上法(bottom-up method)

按从小到大的顺序顺次求解。

// Algorithm 3
BOTTOM-UP-CUT-ROD(p,n)
	let r[0...n] be a new array
	r[0] = 0							// 该方法在代码形式上是非递归的自底向上递推方法(函数并未调用自己)
										// 最后返回 r[n] 而非 q,所以不能像上面在 if-else 语句中使 q=0 赋值并返回
										// 而必须在前面直接指定 r[0] = 0 作为递推的初始条件
	for j = 1 to n
		q = -∞
		for i = 1 to j
			q = max(q,p[i]+r[j-i])
		r[j]=q
	return r[n]

子问题图

自顶向下递归调用树的简化版,是有向图,边 (x, y) 表示 x 的求解依赖 y 。自底向上处理顺序是子问题图的逆序。

解重构

不仅要求出最优收益,还要求出切割方案。

// Algorithm 4
EXTENDED-BOTTOM-UP-CUT-ROD(p,n)
	let r[0...n] and s[0...n] be new arrays
	r[0] = 0
	for j = 1 to n
		q = -∞
		for i = 1 to j
			if q < p[i] + r[j-1]
				q = p[i] + r[j-i]				// 不能直接写max,因为同时还要使s[j]=i
				s[j] = i						// 记录各个长度钢条最优的“第一刀”
		r[j] = q
	return r[n]
PRINT-CUT-ROD-SOLUTION(p,n)
	(r,s) = EXTENDED-BOTTOM-UP-CUT-ROD(p,n)
	while n > 0
		print s[n]
		n = n - s[n]							// 递推打印最优切割方案

矩阵链乘法

给定 n 个矩阵的链,矩阵 Ai 的维数为 pi-1 × pi 。求一个完全“括号化方案”,使得计算该矩阵链乘积所需的标量乘法次数最小。

前置知识

矩阵乘法:C = Ap×r × Br×q = (cij)p×q,其中 cij = Σ1≤k≤r (aikbkj) ,i = 1, 2, ..., p, j = 1, 2, ..., q,共需 pqr 次标量乘法运算。

矩阵链乘法:

\[< {A_1},{A_2},...,{A_n} > \]

满足结合律。

// Algorithm 1
MATRIX-MULTIPLY(A,B)
if A.columns != B.rows
	error
else let C be a new A.rows × B.columns matrix
	for i = 1 to A.rows
		for j = 1 to B.columns
			c(ij) = 0
			for k = 1 to A.columns
				c(ij) = c(ij) + a(ik)*b(kj)
return C

求解

令 P(n) 表示所有的括号化方案数量。有

\[{P_n} = \left\{ \begin{array}{l} 1,n = 1\\ \sum\limits_{k = 1}^{n - 1} {P(k)P(n - k),n = 2} \end{array} \right. \]

且易证 P(n) = Ω(2n) 。

  1. 最优子结构性的证明(反证法)。
  2. 递归求解方案:(记 m[i,j] 为矩阵链乘法 Ai,j 标量乘法运算次数最优解,s[i,j] 为使 m[i,j] 最优时的k,Ai,j 的最优括号化方案的分割点在 Ak 与 Ak+1 之间)

\[m(i,j) = \left\{ \begin{array}{l} 0,i = j\\ \mathop {\min }\limits_{i \le k < j} \{ m[i,k] + m[k + 1,j] + {p_{i - 1}}{p_k}{p_j}\} ,i < j \end{array} \right. \]

自底向上表格法

// Algorithm 2
MATRIX-CHAIN-ORDER(p)
	n = p,length - 1
	let m[1..n,1..n] and s[1..n,1..n] be new tables		// “表格”即二维数组
	for i = 1 to n
		m[i,i] = 0
	for l = 2 to n										// 选取的矩阵链长度
		for i = 1 to n-l+1								// 该矩阵链长度的初始下标
			j = i+l-1									// 由该矩阵链长度的初始下标计算最后一位的下标
			m[i,j] = ∞
			for k = i to j-1
				q = m[i,k] + m[k+1,j] + p(i-1)p(k)p(j)
				if q < m[i,j]
					m[i,j] = q
					s[i,j] = k
	return m and s
		

可作出对应的 m 表和 s 表(如图15-5)。

  1. 时间复杂度:Ω(n3),空间复杂度:Θ(n2)。

  2. 构造最优解。

// Algorithm 3
PRINT-OPTIMAL-PARENS(s,i,j)
	if i==j
		print "A"(i)
	else print "("
		PRINT-OPTIMAL-PARENS(s,i,s[i,j])
		PRINT-OPTIMAL-PARENS(s,s[i,j]+1,j)
		print ")"

动态规划的一般方法

决策,决策变量,决策序列,多阶段决策过程

无后效性:对任意阶段 i ,阶段 i 以后的行为仅依赖于 i 阶段的状态,而与 i 阶段之前是如何达到这种状态的无关。

状态转移方程:xi+1 = Ti ( x(i) , u(i) )。

多阶段决策过程的最优化问题即求对应的最优决策序列,方法:枚举法、动态规划。

最优化原理(Principle of Optimality):过程的最优决策序列具有以下性质:无论初态和初始决策如何,其余决策必须相对于初始决策产生的状态构成一个最优决策序列。

子问题无关性。e.g. 最短路径问题具有最优子结构性。最长简单路径问题不具有最优子结构性。最优子结构性的证明:“剪切-粘贴”(cut-and-paste)技术,即反证法。

若问题的决策序列由 n 次决策构成,而每次决策有 p 种选择,则可能的决策序列将有 pn 个。利用动态规划策略的求解过程中仅保存了所有子问题的最优解,舍去了不能导致最优解的次优决策序列,可能有多项式的计算复杂度。

posted on 2024-12-11 19:44  汐寻  阅读(151)  评论(0)    收藏  举报