演算法筆記 動態規劃1

2021-09-07 20:52:25 字數 3114 閱讀 5196

動態規劃適合求解最優問題,比如最大值最小值等。它可以顯著的降低時間複雜度,提高**的執行效率。

0-1 揹包問題

在上篇總結中,用回溯演算法解決了 0-1揹包問題。但是,在求解的過程中,我們應該能想象的出,有些步驟是一直在重複執行。如果揹包的總載重為 9 ,物品個數為 5 ,質量分別為 [2,2,4,6,3]。那麼將這些資料帶入回溯演算法的**中,執行階段用遞迴樹來表示:

在上圖中遞迴樹中每個節點的狀態,用 (i,cw) 來表示。i 表示要決策第幾個物品是否放入揹包,cw 代表當前揹包的總質量。例如 (2,2) 代表第二個物品將決定是否放入揹包,決策之前揹包的總質量是 2。

通過上面的圖例加說明,我們可以看出 f(2,2) 和 f(3,4) 都被重複計算了兩次。為了減少重複計算的次數,我們可以把計算過的情況記錄在案,當下次遇到相同的計算的時候,直接取值用就好。**如下:

// 儲存揹包中物品總重量的最大值

public

int maxw = integer.min_value;

private

int[

] weight =

;// 物品重量

private

int n =5;

// 物品個數

private

int w =9;

// 揹包承受的最大重量

private

boolean

mem =

newboolean[5

][10]

;// 備忘錄,預設值 false

/** *

* @param i 表示任務進行的階段,考察到哪個物品了

* @param cw 表示當前已經裝進去的物品的重量和

* @param items 陣列存放每個物品的質量

*/public

voidf(

int i,

int cw)

return;}

if(mem[i]

[cw]

) mem[i]

[cw]

=true

;// 記錄 (i, cw) 這個狀態

//該物品不放入揹包

f(i +

1, cw)

;//該物品放入揹包,物品放入揹包的時候,需要判斷當前物品總質量是否小於等於揹包的承載重量

if(cw + weight[i]

<= w)

}

上面的過程理解之後,接下來總結動態規劃如何實現上面的過程。

求解的過程分解成 n 個階段,n 代表物品的數量。每個階段,決定乙個物品是否放入,決策之後,揹包的重量會發生變化,這個變化的狀態對應到遞迴樹中就是不同的節點。

現在,我們把遞迴樹中每一層中相同狀態的節點合併,只留下不同狀態的集合,並且在本次狀態集合下去推導下一次的狀態集合。由於我們值儲存不相同的狀態,並且總重量不能大於 w (w 代表總重量),所以每層的狀態集合最多有 w 個。(此處補充一下:前提是物品的質量都是整數,不可分割。)這樣我們就避免了每一層的結果整合指數增長。

針對每一層的狀態集,建立乙個 states[n][w + 1] 二維陣列來儲存。n 代表層級,w + 1 代表結果集區間是從 0 到 w + 1。

對於放入第 0 個物品,質量為 2 ,對應陣列中就是 states[0][0] = true,states[0][2] = true。states[0][0] 代表沒有放入,states[0][2] 代表放入。以此類推,整個過程就是如下圖所示:

**如下:

// weight: 物品重量,n: 物品個數,w: 揹包可承載重量

public

intknapsack

(int

weight,

int n,

int w)

}// 把第 i 個物品放入揹包

// w - weight[i] 代表該物品放入之後,只有 j 以及 j 前面的不超重

for(

int j =

0; j <= w - weight[i]

;++j)}}

for(

int i = w; i >=0;

--i)

return0;

}

上述**中有詳細的注釋,足以看懂整個過程。

上面所舉的例子以及**的實現,就是乙個動態規劃演算法的實現。將問題分階段解決,每個階段都有不同的結果集,我們合併相同的結果集,然後用該結果集去推到下一階段的結果集,這就是乙個動態規劃的過程。

當然,上述**雖然比起回溯演算法提高了效率,但是卻需要額外開闢乙個二維陣列,增加可空間的消耗。下面用**實現一種用一維陣列完成的動態規劃:

public

static

intknapsack2

(int

items,

int n,

int w)}}

for(

int i = w; i >=0;

--i)

return0;

}

上述**之所以可以用一維陣列實現,主要是省略了每一層中物品不放入揹包的邏輯。如果不省略,進行了不放入揹包的判斷,其實只是把上一次的狀態搬移到本層。但是這次搬移其實是無用功的,因為上一層已經滿足的條件,搬移到這一整層,依舊是滿足條件的。所以,有意義的操作就是對本層物品放入的判斷。另外乙個原因,因為是動態規劃,我們都是用上一層的結果集推導下一層的結果集。也就是說,當本層的結果集推導出來後,上一層的結果集已經沒有用處了。所以,我們才可以採用本層額結果集覆蓋上層的結果集,最終完成動態規劃。

總結初入演算法學習,必是步履蹣跚,一路磕磕絆絆跌跌撞撞。看不懂別慌,也別忙著總結,先讀五遍文章先,無他,唯手熟爾~

與諸君共勉

演算法筆記 動態規劃 1

求解方法 標準的01揹包問題是指,有n int型 個物品和最多裝重量w int型 的揹包。weight陣列表示物品的重量,即weight i 表示第i個物品的重量 value陣列表示物品的價值,即value i 表示第i個物品的價值。問把哪些物品裝入揹包使得物品價值總和最大,每個物品只能裝一次。舉例...

演算法 動態規劃(1)

把問題拆分成若干個子問題,類似遞迴 分治 但是動規多用於處理最優解,有重疊子問題的問題,因為動態規劃對於重疊子問題不會反覆計算,會建立一張表將之前計算過的子問題答案直接儲存,避免了重複計算,加快計算速度 練習1 有8個任務,每個任務完成需要一定的時間,完成之後就會有相應的報酬 圖上的紅色字段 但是任...

演算法1 動態規劃

動態規劃的步驟是 1.找出最優解的特徵,並刻畫其結構特徵 2.遞迴地定義最優值 3.以自底向上的方式計算出最優值 4.根據計算最優值的時得到的資訊,構造最優解。動態規劃演算法的有效性依賴於兩個最重要的性質 最優子結構性質和重疊子問題性質。栗子1,矩陣連乘問題。1 動態規劃 矩陣連乘問題 2 incl...