動態規劃——基礎

最佳子結構(optimal substructure)

假設從你家到遠方某城市最便宜的公路旅程恰好途經路上某個小鎮。那麼這段旅程中從你家到該小鎮的部分,本身必定是從家到該鎮最便宜的走法。如果不是——如果有更便宜的方式到達該鎮——你就可以把它換進來,使整段旅程更便宜,這與你原本走的是最佳路線相矛盾。這種「最佳的整體由最佳的部分組成」的現象,就稱為最佳子結構。

嚴謹地說,當一個問題的最佳解內部包含其各子問題的最佳解時,這個問題就具有最佳子結構。這讓你能用較小版本的最佳答案來表達原問題的最佳答案,而這正是動態規劃核心的遞迴關係式。確立它的論證幾乎總是「剪下貼上」式的證明:取一個號稱最佳的解,假設其中某個嵌入的片段對它自己的子問題並非最佳,把更好的片段貼進去,再證明整個解會變得更好——產生矛盾。以兩個結尾字母相同的字串的最長共同子序列為例,最佳對齊必定用上這個共同的末字母,再對它前面的部分做最佳對齊,否則你還能把它加長。

這個性質正是貪婪法與動態規劃得以成立的基礎,而它的缺席同樣富含資訊。圖上的最長簡單路徑就著名地缺乏最佳子結構:從 A 經 B 到 C 的最長簡單路徑未必能拆成「A 到 B 的最長路徑」加「B 到 C 的最長路徑」,因為兩半可能共用頂點,合起來就破壞了「簡單」(不重複經過頂點)的條件。所以你必須用真正的論證去驗證最佳子結構,而不能想當然——它可能悄悄地失效。

最短路徑具有最佳子結構:若從 s 到 t 的最短路徑走 s -> u -> ... -> v -> t,則其中 s 到 v 的那段就是 s 到 v 的最短路徑。剪下貼上:把一段更短的 s 到 v 貼進來,就會得到更短的 s 到 t 路徑,與最佳性矛盾。這正是以鬆弛為基礎的演算法能運作的原因。

剪下貼上把「某子片段並非最佳」推成矛盾,從而證明最佳子結構。

最佳子結構對貪婪法和動態規劃都是必要的,但它本身分不出兩者——貪婪法還額外需要貪婪選擇性質,而動態規劃只需要你把所有子問題組合都試過。而且它可能失效(最長簡單路徑),所以要去證明它。

又称
optimal-substructure property最優子結構