作者:劉子韜
Dynamic Programming 中的 Programming 指「表格法」,而非編程。核心:用表格保存子問題結果,避免遞歸重複計算。
與分治區別:分治子問題獨立,DP 子問題重疊。
長度 n 米鋼條,價格表 p[i](長度 i 價格)。求切割方案最大化收益。
第一刀切在 i 處:收益 = p[i] + Cut(n-i)。遍歷 i 取最大值。
Cut(P, n):
if n == 0: return 0
q = -∞
for i = 1 to n:
q = max(q, P[i] + Cut(P, n-i))
return q
Cut(P, n):
r[0] = 0
for i = 1 to n:
q = -∞
for j = 1 to i:
q = max(q, P[j] + r[i-j])
r[i] = q
return r[n]
序列 X (長 n)、Y (長 m),求最長公共子序列長度。
設指針 i, j 分別指向 X, Y 末尾:
// 初始化:第 0 行/列 = 0
for i = 1 to m:
for j = 1 to n:
if X[i] == Y[j]:
LCS[i,j] = LCS[i-1,j-1] + 1
else:
LCS[i,j] = max(LCS[i,j-1], LCS[i-1,j])
矩陣鏈 A₁...Aₙ,Aᵢ 為 Pi-1×Pi。求乘法順序使標量乘法次數最小。
在 k 處分割:m[i,j] = mini≤k
基例:i==j 時 m[i,j]=0
// 初始化:對角線 = 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
輸入 X₁...Xₙ,構造枚舉樹:每層決定「選/不選」當前元素。

維護數組 tail[len] 存儲長度為 len 的遞增子序列最小末尾值。遍歷輸入,二分查找插入位置更新 tail。最終 tail 長度即 LIS 長度。
動態規劃核心三要素:重疊子問題、最優子結構、無後效性。兩大設計路徑各有千秋:遞歸+備忘錄直觀易寫;窮盡搜索+剪枝揭示問題結構,適合複雜約束場景。經典案例展示了從 1D 到 2D 表格的構建模式,掌握「狀態定義 → 轉移方程 → 初始化 → 計算順序」四步法,DP 諸題迎刃而解。