為什麼線性動態規劃類問題通常使用遞推求解子問題,而不使用記憶化遞歸?
例如揹包問題,通常我們使用一個 dp[i][j] 數組記錄子問題的解,依次從小到大求解所有子問題。使用記憶化遞歸也可以完成這類工作(例如定義一個 dp(i,j)函數),這樣做只需求解必要的少數幾個子問題即可得到題目的解,不用求解所有子問題。這看似比傳統的遞推做法還快。那為什麼人們常用遞推而不用記憶化遞歸?
- 不同的題目用不同的寫法比較方便;
- 記憶化有時候空間複雜度更高。
關於揹包,遞推可以滾動數組優化,遞歸就不行。
首先
這兩種寫法的時間複雜度是一樣的
其次
這兩種寫法都很常用,只是對於許多特定的問題
用遞推會減少代碼長度而且看著更優美
遞歸的寫法
您可以來看看【P3953】逛公園 - 洛谷
遞歸形式相對於遞推形式有以下幾個優點:
- 更直觀,一旦寫出狀態轉移方程,遞歸形式就相當於「模擬題」了。
- 在某些情況下,遞歸能少訪問一些子問題。
- 拓撲序列不明,即很難找到子問題之間的執行先後順序,比如一個亂七八糟的遞歸函數。
其中,1. 存在於所有 dp 題中,但 2. 和 3. 極少出現。
而遞推形式有如下優點:
- 省時間省空間。減少子程序的調用,降低時間函數中的常數。
- 程序短一些
- 提供更廣闊的優化空間。有時可以覆蓋數據,從而大大降低空間複雜度(不只是優化常數)。
題主提到了 01揹包,這可以說是3.的體現。其實圖論中的 floyd 演算法 也是把數據覆蓋減小到 的空間複雜度的。
詳細解釋: