在看了揹包九講以及這篇博文之後,對於01揹包有了更好的理解,下面整理一下以備以後回顧之用。
首先,說明一下什麼是01揹包問題。
一共有n個物品,每個物品的價值是w[i],重量是c[i],給你乙個容量為v的揹包,問從這n個物品中選取若干件所能獲得的最大價值是多少。
我們考慮一下第i件物品。以陣列f[i][j]表示前i件物品,在j的揹包容量下可以獲得的最大價值。
很明顯的是,對於第i件物品,只有取或者不取兩種狀態,那麼f[i][j]就是:
下面就很容易給出**
for(int i = 1 ; i <= n ; i ++)
到這個地方應該是沒有問題的。
這段**的空間複雜度和時間複雜度都是o(vn),我們想優化一下。時間複雜度不可能優化了....(我覺得不可能),揹包九講的作者想到的就是從空間複雜度上優化。即只用一維陣列f[j]來取代f[i][j]。
可能我智商不行....原作者講的我看不太懂。看了一些列的資料以後才慢慢明白一點。
我們想用f[j]來取代f[i][j],那麼就必須明確f[j]儲存的是什麼狀態。
定義:f[j]表示的是在揹包容量為j的情況下,n件物品所能取得的最大價值。
(f[i][j]表示的是前i件物品在揹包容量為j的情況下所能取得的最大i價值)
其實看上邊這一段**,容易看出,f[i][j]的狀態只和f[i-1][j]和f[i-1][j-c[i]]有關,即只和i-1時刻的狀態有關係,我們用乙個一維陣列
f來儲存各個時刻的狀態(假設不同的i代表不同的時刻)
(f[j]表示的是把前i件物品放進揹包容量為j的揹包中,i從1-n迴圈完畢後就是n件物品選取若干件放入揹包容量為j的揹包中的價值)
那麼給一組測試資料結合例子看看
10,3, 3,4 4,5, 5,6
c[v]從物品i=1開始,迴圈到物品3,期間,每次逆序得到容量v在前i件物品時可以得到的最大值。
(看著這個圖自己寫寫畫畫的確明白必須是逆序的...但是自己想還是想不到的...)
所以**如下:
for(int i = 0 ; i < n ; i++)
附註:
有的問題可能會讓我們把取的物品編號列印出來...
對於f[i][j]這種狀態轉移方程其實很好判斷,只要f[i][j]==f[i-1][j-c[i]]+w[i]說明包裡面有第i件物品,然後列印編號即可。
如果是f[i]這種方式,是沒有辦法用f[j]==f[j-c[i]]+w[i]來判斷的...這時候可以找乙個二維陣列path[i][j]記錄下來...**如下:
for(int i = 0 ; i < n ; i++)
}
列印時,逆序尋找(必須是逆序的...)
**如下:
int i = n, j = v;
while(i > 0 && j > 0)
i--;
}
動態規劃法求解簡單的 0 1 揹包問題
動態規劃法是一種強有力的演算法設計技術,它被廣泛用於求解組合最優化問題。這種技術採用自底向上的方式遞推求值,將待求解的問題分解成若干個子問題,先求解子問題,並把子問題的解儲存起來以便以後用來計算所需要求的解。為了設計一種動態規劃演算法,需要推導出乙個遞推關係,用較小例項的解的形式來表示揹包問題的例項...
動態規劃求解01揹包相關的基本問題
揹包問題是經典問題,網上已經提供了很多優秀的解法,這裡摘錄動態規則的方法,同時順便把揹包相關的變形問題也一些闡述。問題 1.經典揹包問題 給定乙個載重量為m,n個物品,其重量為wi,價值為vi,1 i n,要求 把物品裝入揹包,並使包內物品價值最大。2.變形 要求裝入的物品重量最大?問題很簡單,但請...
用回溯法求解0 1揹包問題,並輸出問題的最優解
問題 給定n種物品和一揹包。物品i的重量是wi,其價值為vi,揹包的容量是c,問應如何選擇裝入揹包中的物品,使得裝入揹包中物品的總價值最大。0 1揹包問題是乙個子集選取問題,適合於用子集樹表示0 1揹包問題的解空間。在搜尋解空間樹是,只要其左兒子節點是乙個可行結點,搜尋就進入左子樹,在右子樹中有可能...