1957-Bellman動態規劃#
案件摘要#
1957 年,理查德·貝爾曼(Richard Bellman)在普林斯頓大學出版社出版《Dynamic Programming》,為「多階段決策問題」建立了一套完整的理論與方法。案件的偵查對象是一類線性規劃無法處理的難題:決策是一連串相互牽動的選擇,眼前的最優選擇未必導致全域最優。貝爾曼的破案武器是「最佳化原理」——最優策略的任何子策略也必是最優的——這條原理把大問題拆成無數互相重疊的小問題,再用一張表格把每個小問題的答案存起來,徹底消滅重複計算。
前因 -- 為什麼會有這個案子#
- RAND 公司(RAND Corporation)在 1950 年代投入控制論與最優控制研究,面臨的核心問題是多階段決策:飛彈導引、庫存管理、資源分配都要求在時間軸上一連串做出最優選擇。
- Dantzig 的線性規劃(1947)只能處理單階段的線性約束問題,對多階段、非線性、隨機性的決策問題無能為力。
- 貝爾曼在 RAND 有名的「名稱戰術」:他自述刻意選用「dynamic」這個詞,因為時任國防部長嫌「數學」太抽象,而「dynamic」聽起來充滿活力又「有點意思」,經費因此撥得下來——這個名字就這樣定案。
- 1953 年的 RAND 報告已是先聲,其中貝爾曼方程與最佳化原理的雛形已經出現,1957 年的專書則是正式結案陳詞。
線索與推理 -- 數學式、程式、理論#
線索一:最佳化原理與貝爾曼方程#
貝爾曼提出的最佳化原理(principle of optimality):
最優策略具有如下性質:無論初始狀態與初始決策為何,其後的決策對於第一個決策所造成的狀態而言,必定也是一個最優策略。
這條原理把多階段問題化為遞迴的價值函數。以確定性離散系統為例,貝爾曼方程為:
其中 \(V(s)\) 是從狀態 \(s\) 出發的最優總成本, \(c(s,u)\) 是本步成本, \(s'\) 是採取決策 \(u\) 後轉移到的新狀態。問題從終端條件 \(V(T)\) 倒推或自底向上順推求解。
線索二:重疊子問題與最佳子結構#
DP 適用的兩大特徵:
- 最佳子結構(optimal substructure):大問題的最優解由子問題的最優解組成——這正是最佳化原理的代數表現。
- 重疊子問題(overlapping subproblems):遞迴展開時,同一個子問題會被反覆碰到。
對付重疊子問題有兩招:記憶化(memoization,遞迴時把算過的答案存進表格)與自底向上填表(bottom-up tabulation,按依賴順序直接迴圈填表)。兩者的哲學都是「用空間換時間」。
線索三:Fibonacci 的指數 vs 線性對照#
Fibonacci 遞迴 \(F(n) = F(n-1) + F(n-2)\) 的呼叫樹呈指數膨脹,呼叫次數 \(T(n) = T(n-1) + T(n-2) + 1 = \Theta(\varphi^n)\) ( \(\varphi \approx 1.618\) );記憶化後每個 \(F(k)\) 只算一次:
線索四:最長共同子序列(LCS)#
兩序列 \(X[1..m]\) 與 \(Y[1..n]\) 的最長共同子序列滿足遞迴式:
以 \(O(mn)\) 時間與空間填表求解——編輯距離(Levenshtein distance)與之同構。
破案時刻:可執行驗證#
calls_naive = 0
calls_memo = 0
def fib_naive(n):
global calls_naive
calls_naive += 1
if n <= 1:
return n
return fib_naive(n - 1) + fib_naive(n - 2)
memo = {}
def fib_memo(n):
global calls_memo
calls_memo += 1
if n <= 1:
return n
if n not in memo:
memo[n] = fib_memo(n - 1) + fib_memo(n - 2)
return memo[n]
n = 20
assert fib_naive(n) == fib_memo(n) == 6765
print(f"F({n}) = 6765")
print(f"naive 呼叫次數 = {calls_naive}")
print(f"memo 呼叫次數 = {calls_memo}")
def lcs(X, Y):
m, n = len(X), len(Y)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if X[i - 1] == Y[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
print("LCS('ABCBDAB', 'BDCABA') =", lcs("ABCBDAB", "BDCABA"))
執行結果:naive 的 Fibonacci 在 n=20 時已呼叫上萬次(約 \(2F(21)-1 = 21891\) 次),memo 版僅呼叫數十次;LCS 正確回傳 4,實證了「用空間換時間」的威力。
結案 -- 後果與影響#
- 動態規劃成為演算法設計五大範式(分治、貪婪、DP、隨機化、近似)之一,編輯距離、背包問題、矩陣鏈乘、最短路徑(Floyd-Warshall)都有標準 DP 解法。
- 貝爾曼方程成為強化學習的理論基石:價值迭代、策略迭代直接源自 1957 年的框架,Q-learning(Watkins, 1989)與日後的深度強化學習都是貝爾曼方程的近代後裔。
- 最優控制理論(如線性二次調節器 LQR、Hamilton-Jacobi-Bellman 方程)自此有了離散與連續兩條主線。
- 「用空間換時間」成為演算法設計的核心哲學,記憶化成為函數式程式設計與競賽程式的日常工具。
- 貝爾曼本人的「名稱戰術」軼事,也成為科學命名政治學的經典案例。
關鍵人物與文獻#
- Richard Bellman, Dynamic Programming, Princeton University Press, 1957.
- Richard Bellman, "On the Theory of Dynamic Programming", Proceedings of the National Academy of Sciences, 38(8), 1952, pp. 716–719.
- Richard Bellman, RAND Report P-480: The Theory of Dynamic Programming, RAND Corporation, 1953.
- Richard Bellman, Eye of the Hurricane: An Autobiography, World Scientific, 1984(自述「dynamic」名稱戰術)。
- Stuart Dreyfus, "Richard Bellman on the Birth of Dynamic Programming", Operations Research, 50(1), 2002, pp. 48–51.
- Christopher J. C. H. Watkins, Peter Dayan, "Q-learning", Machine Learning, 8, 1992, pp. 279–292.