01背包問題,是用來介紹動態規划算法最經典的例子,網上關於01背包問題的講解也很多,我寫這篇文章力爭做到用最簡單的方式,最少的公式把01背包問題講解透徹。
01背包的狀態轉換方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
題目描述:
有編號分別為a,b,c,d,e的五件物品,它們的重量分別是2,2,6,5,4,它們的價值分別是6,3,5,4,6,現在給你個承重為10的背包,如何讓背包里裝入的物品具有最大的價值總和?
| name | weight | value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| a | 2 | 6 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |
| b | 2 | 3 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 9 | 10 | 11 |
| c | 6 | 5 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 11 |
| d | 5 | 4 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 10 |
| e | 4 | 6 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
只要你能通過找規律手工填寫出上面這張表就算理解了01背包的動態規划算法。
首先要明確這張表是至底向上,從左到右生成的。
為了敘述方便,用e2單元格表示e行2列的單元格,這個單元格的意義是用來表示只有物品e時,有個承重為2的背包,那么這個背包的最大價值是0,因為e物品的重量是4,背包裝不了。
對於d2單元格,表示只有物品e,d時,承重為2的背包,所能裝入的最大價值,仍然是0,因為物品e,d都不是這個背包能裝的。
同理,c2=0,b2=3,a2=6。
對於承重為8的背包,a8=15,是怎么得出的呢?
根據01背包的狀態轉換方程,需要考察兩個值,
一個是f[i-1,j],對於這個例子來說就是b8的值9,另一個是f[i-1,j-Wi]+Pi;
在這里,
f[i-1,j]表示我有一個承重為8的背包,當只有物品b,c,d,e四件可選時,這個背包能裝入的最大價值
f[i-1,j-Wi]表示我有一個承重為6的背包(等於當前背包承重減去物品a的重量),當只有物品b,c,d,e四件可選時,這個背包能裝入的最大價值
f[i-1,j-Wi]就是指單元格b6,值為9,Pi指的是a物品的價值,即6
由於f[i-1,j-Wi]+Pi = 9 + 6 = 15 大於f[i-1,j] = 9,所以物品a應該放入承重為8的背包
1 #include<iostream> 2 using namespace std; 3 #define V 1500 4 unsigned int f[10][V];//全局變量,自動初始化為0 5 unsigned int weight[10]; 6 unsigned int value[10]; 7 #define max(x,y) (x)>(y)?(x):(y) 8 int main() 9 { 10 11 int N,M; 12 cin>>N;//物品個數 13 cin>>M;//背包容量 14 for (int i=1;i<=N; i++) 15 { 16 cin>>weight[i]>>value[i]; 17 } 18 for (int i=1; i<=N; i++) 19 for (int j=1; j<=M; j++) 20 { 21 if (weight[i]<=j) 22 { 23 f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]); 24 } 25 else 26 f[i][j]=f[i-1][j]; 27 } 28 29 cout<<f[N][M]<<endl;//輸出最優解 30 }
可以進一步優化內存使用。上面計算f[i][j]可以看出,在計算f[i][j]時只使用了f[i-1][0……j],沒有使用其他子問題,因此在存儲子問題的解時,只存儲f[i-1]子問題的解即可。這樣可以用兩個一維數組解決,一個存儲子問題,一個存儲正在解決的子問題。
再進一步思考,計算f[i][j]時只使用了f[i-1][0……j],沒有使用f[i-1][j+1]這樣的話,我們先計算j的循環時,讓j=M……1,只使用一個一維數組即可。
for i=1……N
for j=M……1
f[j]=max(f[j],f[j-weight[i]+value[i])
1 #include<iostream> 2 using namespace std; 3 #define V 1500 4 unsigned int f[V];//全局變量,自動初始化為0 5 unsigned int weight[10]; 6 unsigned int value[10]; 7 #define max(x,y) (x)>(y)?(x):(y) 8 int main() 9 { 10 11 int N,M; 12 cin>>N;//物品個數 13 cin>>M;//背包容量 14 for (int i=1;i<=N; i++) 15 { 16 cin>>weight[i]>>value[i]; 17 } 18 for (int i=1; i<=N; i++) 19 for (int j=M; j>=1; j--) 20 { 21 if (weight[i]<=j) 22 { 23 f[j]=max(f[j],f[j-weight[i]]+value[i]); 24 } 25 } 26 27 cout<<f[M]<<endl;//輸出最優解 28 }
