思想 & 基本要素
先講一個問題來了解動態規劃算法的思想
矩陣連乘問題
問題描述:給定 n 個矩陣 { A1, A2, … , An } 其中相鄰的矩陣是可乘的,求它們的連乘積 A1, A2, … , An
完全加括號:以加括號的形式,明確指明矩陣連乘的計算順序,記爲 ( A1, A2, … , An )
不同的完全加括號式對應不同的運算次數
矩陣連乘問題即爲尋找運算次數最小的完全加括號式
窮舉搜索法
再思考下列問題:
分治算法的三個要點:子問題與原問題的性質相同,子問題的求解彼此獨立,劃分子問題的規模儘可能均衡
若分解的子問題不是互相獨立的?
分治法的子問題如下圖:
動態規劃的子問題如下圖:
重複計算導致複雜性急劇提高,甚至達到指數階
Catalan數列
指數階
求解中子問題存在大量的重複
實際上所有的子問題只有10個
A1, A2, A3, A4, A1A2, A2A3, A3A4, A1A2A3, A2A3A4, A1A2A3A4
動態規劃的兩個基本要素
第一個要素:最優子結構性質
- 問題的最優解包含了子問題的最優解
- 原問題可以通過分解子問題來解決
第二個要素:重疊子問題性質(如:爬樓梯問題、斐波那契數列)
與分治法的主要區別: - 直接遞歸求解子問題的複雜性往往是指數階
- 子問題空間的規模通常是多項式階
- 同一個子問題可能出現在多次問題分解中
動態規劃的求解過程
遞歸 --> 保存 --> 自底向上 / 自頂向下
矩陣連乘問題的求解
動態規劃的複雜性爲 O(n^3)
備忘錄法:自頂向下
動態規劃與備忘錄
- 動態規劃相當於迭代,需要分析子問題的結構,從最小的問題解起
- 備忘錄相當於遞歸,直接從原問題出發,若未解,則向下遞歸調用
- 當所有子問題都至少需要求解一次時,動態規劃較好
- 當子問題空間中的部分子問題不必求解時,備忘錄較好
最長公共子序列
問題描述:求序列 X = { x1, x2, … , xm} 和序列 Y = {y1, y2, … , yn} 最長的公共子序列
窮舉法
找出 X = { x1, x2, … , xm} 的所有子序列,逐個檢查 X子序列是否也是 Y子序列,輸出最長的一個公共子序列,子序列的數量爲 O(2^m)
最優子結構性質
設 X = { x1, x2, … , xm} 和序列 Y = {y1, y2, … , yn} 的最長公共子序列爲 Z = {z1, z2, … , zk} ,則
- Zk-1 是 Xm-1 和 Yn-1 的最長公共子序列
- Z 是 Xm-1 和 Y 的最長公共子序列
- Z 是 X 和 Yn-1 的最長公共子序列
重疊子問題性質
遞歸關係式
動態規劃求解
算法的複雜性爲 O(mn)
0-1揹包問題
問題描述:給定 n 個物品和一個揹包。物品 i 的重量爲 Wi ,價值爲 Vi ,揹包的容量爲 c ,問如何選擇物品,使得揹包中物品的價值最大
動態規劃法
1、最優子結構
設 { x1, x2, … , xn} 是揹包的一種最優裝法,考慮如下子問題:
待裝入物品 { 2, … , n} ,且揹包容量爲 c-W1X1
假設這個子問題的最優解不是 { x2, … , xn},而是 { x’2, … , x’n},則原問題按 { x1, x‘2, … , x’n} 的裝法,得到的總價值最高,與 { x1, x2, … , xn} 是最優裝法的假設矛盾
2、子問題構造
已考察完後 n - i 個物品,剩餘物品爲 1, … , i ,剩餘容量爲 j
設該子問題的最優解爲 m[ i ][ j ]
,原問題爲 m[ 0 ][ c ]
3、遞歸關係式
考察下一個物品 i是否裝入,若 Wi > j,無法裝入,否則,取裝入時和不裝入時價值的較大者
算法的複雜性爲 O(nc)
小結
- 使用動態規劃求解時,應先證明問題的最優子結構性質
- 構造子問題最優解之間的遞歸關係式仍是求解的重點和難點
- 子問題的數量通常是規模的多項式階
- 繪製一維或二維 DP 表是動態規劃的常用手段