動態規劃之01揹包

2021-06-28 17:17:26 字數 2498 閱讀 5320

動態規劃的基本思想:

將乙個問題分解為子問題遞迴求解,且將中間結果儲存以避免重複計算。通常用來求最優解,且最優解的區域性也是最優的。求解過程產生多個決策序列,下一步總是依賴上一步的結果,自底向上的求解。

動態規劃演算法可分解成從先到後的4個步驟:

1. 描述乙個最優解的結構,尋找子問題,對問題進行劃分。

2. 定義狀態。往往將和子問題相關的各個變數的一組取值定義為乙個狀態。某個狀態的值就是這個子問題的解(若有k

個變數,一般用k

維的陣列儲存各個狀態下的解,並可根    據這個陣列記錄列印求解過程。)。

3. 找出狀態轉移方程。一般是從乙個狀態到另乙個狀態時變數值改變。

4.以「自底向上」的方式計算最優解的值。

5. 從已計算的資訊中構建出最優解的路徑。(最優解是問題達到最優值的一組解)

其中步驟1~4是動態規劃求解問題的基礎,如果題目只要求最優解的值,則步驟5可以省略。

01揹包問題具體例子:

假設現有容量10kg的揹包,另外有3個物品,分別為a1,a2,a3。物品a1重量為3kg,價值為4;物品a2重量為4kg,價值為5;物品a3重量為5kg,價值為6。將哪些物品放入揹包可使得揹包中的總價值最大?

這個問題有兩種解法,動態規劃和貪婪演算法。本文僅涉及動態規劃。

先不套用動態規劃的具體定義,試著想,碰見這種題目,怎麼解決?

首先想到的,一般是窮舉法,乙個乙個地試,對於數目小的例子適用,如果容量增大,物品增多,這種方法就無用武之地了。

其次,可以先把價值最大的物體放入,這已經是貪婪演算法的雛形了。如果不新增某些特定條件,結果未必可行。

最後,就是動態規劃的思路了。先將原始問題一般化,欲求揹包能夠獲得的總價值,即欲求前i個物體放入容量為m(kg)揹包的最大價值c[i][m]——使用乙個陣列來儲存最大價值,當m取10,i取3時,即原始問題了。而前i個物體放入容量為m(kg)的揹包,又可以轉化成前(i-1)個物體放入揹包的問題。下面使用數學表示式描述它們兩者之間的具體關係。

表示式中各個符號的具體含義。

w[i] :  第i個物體的重量;

p[i] : 第i個物體的價值;

c[i][m] : 前i個物體放入容量為m的揹包的最大價值;

c[i-1][m] : 前i-1個物體放入容量為m的揹包的最大價值;

c[i-1][m-w[i]] : 前i-1個物體放入容量為m-w[i]的揹包的最大價值;

由此可得:

c[i][m]=max(下圖將給出更具體的解釋)

根據上式,對物體個數及揹包重量進行遞推,列出乙個**(見下表),**來自( ,當逐步推出表中每個值的大小,那個最大價值就求出來了。推導過程中,注意一點,最好逐行而非逐列開始推導,先從編號為1的那一行,推出所有c[1][m]的值,再推編號為2的那行c[2][m]的大小。這樣便於理解。

int c[11][101]; //物品最多為10個,容量最大為100kg

int knapsack(int m,int n)

這個方程非常重要,據說基本上所有跟揹包相關的問題的方程都是由它衍生出來的。所以詳細的查了一下這個方程的含義:「將前i件物品放入容量為v的揹包中」這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為乙個只牽扯前i-1件物品的問題。如果不放第i件物品,那麼問題就轉化為「前i-1件物品放入容量為v的揹包中」,價值為f[i-1][v];如果放第i件物品,那麼問題就轉化為「前i-1件物品放入剩下的容量為v-c[i]的揹包中」,此時能獲得的最大價值就是f[i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i]。

在有的地方看到的揹包問題題目中,有兩種不太相同的問法。有的題目要求「恰好裝滿揹包」時的最優解,有的題目則並沒有要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]為0其它f[1..v]均設為-∞,這樣就可以保證最終得到的f[n]是一種恰好裝滿揹包的最優解。

如果並沒有要求必須把揹包裝滿,而是只希望**盡量大,初始化時應該將f[0..v]全部設為0。

為什麼呢?可以這樣理解:初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包可能被價值為0的nothing「恰好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果揹包並非必須被裝滿,那麼任何容量的揹包都有乙個合法解「什麼都不裝」,這個解的價值為0,所以初始時狀態的值也就全部為0了。

部分內容來自:

這裡有一篇01揹包的blog講的十分好:

動態規劃之01揹包

01揹包問題,是用來介紹動態規劃演算法最經典的例子,網上關於01揹包問題的講解也很多,我寫這篇文章力爭做到用最簡單的方式,最少的公式把01揹包問題講解透徹。f i,j 表示在前i件物品中選擇若干件放在承重為 j 的揹包中,可以取得的最大價值。pi表示第i件物品的價值。決策 為了揹包中物品總價值最大化...

動態規劃之01揹包

題目描述 版權說明 本題為改編題。問題描述 發鳩之山,其上多柘木。有鳥焉,其狀如烏,文首,白喙,赤足,名曰精衛,其名自詨。是炎帝之少女,名曰女娃。女娃遊於東海,溺而不返,故為精衛。常銜西山之木石,以堙於東海。山海經 精衛終於快把東海填平了!只剩下了最後的一小片區域了。同時,西山上的木石也已經不多了。...

動態規劃 01揹包

最優二叉查詢樹.cpp 定義控制台應用程式的入口點。01揹包問題。include stdafx.h include include define n 3 the number of real node define m 10 using namespace std int tmain int arg...