背包問題是一個經典的動態規划模型,容易描述,容易理解。背包問題可簡單描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。01背包問題的特點是,每種物品僅有一件,可以選擇放或不放。
01背包問題描述:
有N件物品和一個容量為V的背包。第i件物品的重量是c[i],價值是w[i]。求解將哪些物品裝入背包可使這些物品的重量總和不超過背包容量,且價值總和最大。
寫出狀態轉移方程:
f[i][v]=max{f[i-1][v], f[i-1][v-c[i]]+w[i]}
f[i][v]: 前i件物品恰放入一個容量為v的背包可以獲得的最大價值
f[i-1][v]: 前i-1件物品……(同上),即不放入第i件物品的情況
f[i-1][v-c[i]]+w[i]: 放入第i件物品的情況,放入后的 f[i][v] 應該等於前 i-1 件物品在容量為 v-c[i] 上的最大價值加上 w[i]
空間優化:
f[i][v]=max{f[i-1][v], f[i-1][v-c[i]]+w[i]}
觀察黑色字體部分,發現二維數組完全可以用一維數組替代:
f[v]=max{f[v], f[v-c[i]]+w[i]}
程序怎么寫?循環如何寫?
首先考慮如果所有的物品都能放進去,那一定就是最大價值,如果只能放進去 i (i<N)件物品,那一定要選擇一個最優策略,這個策略的結果是價值最大,而每個 i 的最優策略實際上又是基於 i-1 的最優策略的。根據分析寫出如下循環
for(i=0; i<N; ++i)
for(v=V; v>w[i]; --v) //逆序推能夠保證 f[v-c[i]] 保存的是狀態是 f[i-1][v-c[i]] ,也就是每個物品只被使用了一次;順序的話 f[v-c[i]] 保存的是 f[i][v-c[i]] ,每個物品有可能被使用多次,也就是完全背包問題的解法。
f[v]=max(f[v], f[v-c[i]]+w[i])
poj上的3264題就是一道簡單的01背包問題,http://poj.org/problem?id=3624
我的代碼如下:

1 #include <stdio.h> 2 #define max(x, y) ((x)>(y) ? (x) : (y)) 3 int w[3403]; 4 int d[3403]; 5 int f[13000]; 6 int main() 7 { 8 int i, j, n, m; 9 int nMax = 0; 10 scanf("%d %d", &n, &m); 11 for(i=0; i<n; ++i) 12 { 13 scanf("%d %d", &w[i], &d[i]); 14 } 15 for(i=0; i<n; ++i) 16 { 17 for(j=m; j>=w[i]; --j) 18 { 19 //printf("%d %d %d %d %d %d %d\n", __LINE__, j, i, f[j], w[i], d[i], f[j-w[i]]+d[i]); 20 f[j] = max(f[j], f[j-w[i]]+d[i]); 21 } 22 } 23 printf("%d\n", f[m]); 24 return 0; 25 }
poj上1384是一道完全背包問題,不過該問題求解的最小值,跟求最大值的最主要區別是小心初始化狀態數組。http://poj.org/problem?id=1384
這里也給出代碼:

1 #include <stdio.h> 2 #define min(x, y) ((x)<(y) ? (x) : (y)) 3 #define MAX_INT 10000000 4 int p[501]; 5 int w[501]; 6 int f[10001]; 7 int main() 8 { 9 int t; 10 scanf("%d", &t); 11 while(t--) 12 { 13 int i, j, E, F, n, W; 14 for(i=0; i<10001; ++i) 15 { 16 f[i] = MAX_INT;//注意初始化 17 } 18 f[0] = 0; //注意初始化 19 scanf("%d %d", &E, &F); 20 scanf("%d", &n); 21 W = F-E; 22 for(i=0; i<n; ++i) 23 { 24 scanf("%d %d", &p[i], &w[i]); 25 } 26 for(i=0; i<n; ++i) 27 { 28 for(j=w[i]; j<=W; ++j) 29 { 30 f[j] = min(f[j], f[j-w[i]] + p[i]); 31 } 32 } 33 if(f[W] != MAX_INT) 34 { 35 printf("The minimum amount of money in the piggy-bank is %d.\n", f[W]); 36 } 37 else 38 { 39 printf("This is impossible.\n"); 40 } 41 } 42 return 0; 43 }