01揹包問題ios
問題:有N件物品和一個容量爲V的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可以使價值總和最大。 數組
分析:優化
這是最基礎的揹包問題,特色是:每種物品僅有一件,能夠選擇放或不放。 spa
用子問題定義狀態:即f[i][v]表示前i件物品恰放入一個容量爲v的揹包能夠得到的最大價值。則其狀態轉移方程即是:code
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
xml
這個方程很是重要,基本上全部跟揹包相關的問題的方程都是由它衍生出來的。因此有必要將它詳細解釋一下:「將前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]。blog
優化:io
以上方法的時間和空間複雜度均爲O(VN),其中時間複雜度應該已經不能再優化了,但空間複雜度卻能夠優化到O。編譯
先考慮上面講的基本思路如何實現,確定是有一個主循環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-c[i]]兩個子問題遞推而來,可否保證在推f[i][v]時(也即在第i次主循環中推f[v]時)可以獲得f[i-1][v]和f[i-1] [v-c[i]]的值呢?事實上,這要求在每次主循環中咱們以v=V..0的順序推f[v],這樣才能保證推f[v]時f[v-c[i]]保存的是狀態 f[i-1][v-c[i]]的值。僞代碼以下:class
for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};
代碼實現:
1 /***************01揹包問題******************/ 2 #include <iostream> 3 4 using namespace std; 5 #define INF -65536 6 const int V=1000;//定義體積的最大值; 7 const int T=5;//定義商品的數目; 8 int f[V+1]; 9 //#define EMPTY 10 int w[T]={6,8,3,9,2};//商品的價值; 11 int c[T]={400,600,500,600,900};//商品的體積; 12 int package() 13 { 14 #ifdef EMPTY//能夠不裝滿 15 for(int i=0;i<=V;i++)//條件編譯,表示能夠不存儲滿 16 { 17 f[i]=0; 18 } 19 #else//必須裝滿 20 f[0]=0; 21 for(int i=1;i<=V;i++)//條件編譯,表示必須存儲滿 22 { 23 f[i]=INF; 24 } 25 #endif // EMPTY 26 for(int i=0;i<T;i++) 27 { 28 for(int v=V;v>=c[i];v--) 29 { 30 f[v]=max(f[v],f[v-c[i]]+w[i]); 31 } 32 } 33 return f[V]; 34 } 35 int main() 36 { 37 int temp; 38 temp=package(); 39 cout<<temp<<endl; 40 return 0; 41 }
說
咱們看到的求最優解的揹包問題題目中,事實上有兩種不太相同的問法。有的題目要求「剛好裝滿揹包」時的最優解,有的題目則並無要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不一樣。
若是是第一種問法,要求剛好裝滿揹包,那麼在初始化時除了f[0]爲0其它f[1..V]均設爲-∞,這樣就能夠保證最終獲得的f[N]是一種剛好裝滿揹包的最優解。
若是並無要求必須把揹包裝滿,而是隻但願價格儘可能大,初始化時應該將f[0..V]所有設爲0。
爲何呢?能夠這樣理解:初始化的f數組事實上就是在沒有任何物品能夠放入揹包時的合法狀態。若是要求揹包剛好裝滿,那麼此時只有容量爲0的揹包可能被價值爲0的nothing「剛好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。若是揹包並不是必須被裝滿,那麼 任何容量的揹包都有一個合法解「什麼都不裝」,這個解的價值爲0,因此初始時狀態的值也就所有爲0了。
明: