1. 程式人生 > >【算法】基礎背包

【算法】基礎背包

原來 復雜度 data- evel 遞推 得到 最終 解決方案 代碼

基礎背包

題目

有N件物品和一個容量為V的背包。第i件物品的重量是w[i],價值是v[i]。求解將哪些物品裝入背包可使這些物品的重量總和不超過背包容量,且價值總和最大。

基本思路

這是最基礎的背包問題,特點是:每種物品僅有一件,可以選擇放或不放。 用子問題定義狀態:即f[i][v]表示前i件物品恰放入一個容量為v的背包可以獲得的最大價值。則其狀態轉移方程便是: f[i][v]=max{ f[i-1][v], f[i-1][v-w[i]]+v[i] }。 可以壓縮空間,f[v]=max{f[v],f[v-w[i]]+v[i]} 這個方程非常重要,基本上所有跟背包相關的問題的方程都是由它衍生出來的。所以有必要將它詳細解釋一下:“將前i件物品放入容量為v的背包中”這個子問題,若只考慮第i件物品的策略(放或不放),那麽就可以轉化為一個只牽扯前i-1件物品的問題。如果不放第i件物品,那麽問題就轉化為“前i-1件物品放入容量為v的背包中”,價值為f[i-1][v];如果放第i件物品,那麽問題就轉化為“前i-1件物品放入剩下的容量為v-w[i]的背包中”,此時能獲得的最大價值就是f [i-1][v-w[i]]再加上通過放入第i件物品獲得的價值v[i]。 註意f[v]有意義當且僅當存在一個前i件物品的子集,其費用總和為f[v]。所以按照這個方程遞推完畢後,最終的答案並不一定是f[N] [V],而是f[N][0..V]的最大值。如果將狀態的定義中的“恰”字去掉,在轉移方程中就要再加入一項f[v-1],這樣就可以保證f[N] [V]就是最後的答案。至於為什麽這樣就可以,由你自己來體會了。

空間復雜

以上方法的時間和空間復雜度均為O(N*V),其中時間復雜度基本已經不能再優化了,但空間復雜度卻可以優化到O(V)。 先考慮上面講的基本思路如何實現,肯定是有一個主循環i=1..N,每次算出來二維數組f[i][0..V]的所有值。那麽,如果只用一個數組f [0..V],能不能保證第i次循環結束後f[v]中表示的就是我們定義的狀態f[i][v]呢? f[i][v]是由f[i-1][v]和f [i-1][v-w[i]]兩個子問題遞推而來,能否保證在推f[v]時(也即在第i次主循環中推f[v]時)能夠得到f[v]和f[v -w[i]]的值呢?事實上,這要求在每次主循環中我們以v=V..0的順序推f[v],這樣才能保證推f[v]時f[v-w[i]]保存的是狀態f[i-1][v-c[i]]的值。偽代碼如下: for i=1..N for v=V..0 f[v]=max{f[v],f[v-w[i]]+v[i]}; 其中的f[v]=max{f[v],f[v-w[i]]}一句恰就相當於我們的轉移方程f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]},因為的 f[v-w[i]]就相當於原來的f[i-1][v-w[i]]。如果將v的循環順序從上面的逆序改成順序的話,那麽則成了f[i][v]由f[i][v-w[i]]推知,與本題意不符,但它卻是另一個重要的背包問題P02最簡捷的解決方案,故學習只用一維數組解01背包問題是十分必要的。

【算法】基礎背包