書中以揹包為例子,和樹狀dp 不同,是種一維dp.
如果不記憶化,複雜度為o(n^2)
只不過,這種方法的搜尋深度是n,而且每一層的搜尋都需要兩次分支,最壞就需要o(2」)的時間,
當n比較大時就沒辦法解了。所以要怎麼辦才好呢?為了優化之前的演算法,我們看一下針對樣例
輸入的情形下rec遞迴呼叫的情況。
如圖所示,rec以(3,2)為引數呼叫了兩次。如果引數相同,返回的結果也應該相同,於是第二次調
用時已經知道了結果卻白白浪費了計算時間。讓我們在這裡把第一次計算時的結果記錄下來,省
略掉第二次以後的重複計算試試看。
記憶化搜尋後就僅需o(nw)的複雜度(注*:n是物品個數,w是揹包狀態)
講解了記憶化搜尋的***(見圖一)和不利於記憶化搜尋的***(見碼二)
碼一:
int dp[max_n +1]
[max_w +1]
;//記憶化陣列
intrec
(int i,
int j)
//將結果記錄在陣列中
return dp[i]
[j]= res;
void
solve()
碼二:
窮竭搜尋的寫法
如果對記憶化搜尋還不是很熟練的話,可能會把前面的搜尋寫成下面這樣
// 目前選擇的物品價值總和是sum,從第1個物品之後的物品中挑選重量總和小於j的物品
intrec
(int i,
int j,
int sum)
{int res;
if(i ==n)
{//已經沒有剩餘物品了
res = sum;
} else
if(j//無法挑選這個物品
res =
rec(i +
1, j, sum)
;} else
{//挑選和不挑選的兩種情況都嘗試一下
res =
max(
rec(i +
1, j, sum)
,rec
(i +
1, j - w[i]
, sum +v[i]))
;return res;
在需要剪枝的情況下,可能會像這樣把各種引數都寫在函式上,但是在這種情況下會讓記憶
化搜尋難以實現,需要注意。
兩者的區別就是前者是返回截止每層的最大值(每層皆返回)
數都寫在函式上,但是在這種情況下會讓記憶
化搜尋難以實現,需要注意。
兩者的區別就是前者是返回截止每層的最大值(每層皆返回)
後者是到最後才返回,這樣的動態規劃不利於每層都記錄。
動態規劃學習記錄
動態規劃一般用陣列記錄下每一步的最優值,返回最後一步的值就是最優結果,相對於遞迴解法消除了重複計算的部分,提高的效率。計數 有多少種方式從a到b 多少種方式取得某值 求最優解 最大值最小值 路徑上最大資料和。存在性問題 能不能選出和為k的數 選定演算法前一定要判斷是否為動態規劃解題 有時候問題相似但...
經典動態規劃學習記錄
動態規劃本質是一種用空間換時間的優化方法,通常來優化可以暴力搜尋求解的問題,也就是去冗餘,把之前計算過的存下來,而且是規定了遞迴的計算順序,從簡單基本的出發,依次計算 這也是他優於記憶搜尋的地方 方法大概如下 1.首先能明白暴力遞迴怎麼實現 重要 2.找到函式中可以代表遞迴過程的引數 3.引數為ke...
利用動態規劃方法求素數
因為任何乙個正整數都可以通過素數相乘得到,由此我們可以知道 素數可以視為不能被小於它 或它的平方根 的素數整除的數。通過動態規劃的思想,很容易聯想到,如果將求得的素數儲存起來,那麼在計算後面的素數時,只需要遍歷求模已求得的素數表,而避免進行過多的無效操作。以下為 include include in...