【問題描述】
0-1背包問題:有 N 個物品,物品 i 的重量為整數 wi >=0,價值為整數 vi >=0,背包所能承受的最大重量為整數 C。如果限定每種物品只能選擇0個或1個,求可裝的最大價值。
可以用公式表示為:

動態規划法。我們可以想到這個問題具有最優子結構性質,假設(x1,x2,...,xn)是最優解,那么在去除x1之后,剩下(x2,...,xn)肯定是以下問題的最優解:
根據這個特征可以設計DP函數並推出遞歸關系。具體地,m(i,j)是背包容量為j,可選擇物品為i,i+1,…,n時0-1背包問題的最優值。由0-1背包問題的最優子結構性質,則:
按着DP[N][C]的矩陣一個一個從 下 往 上 填就可以了,最后的結果是 DP(1,C)。要輸出選取的樣本編號的時候可以從前往后, DP(1,C)== DP(2,C),則x1=0,否則1,依次類推即可。
【代碼】
1 #include<iostream> 2 #include<algorithm> 3 #include <stdio.h> 4 #define MAXN 10000 5 using namespace std; 6 7 int W[MAXN]; 8 int V[MAXN]; 9 int DP[MAXN][MAXN]= {0}; 10 11 int knapsack(int C, int N, int W[], int V[], int DP[][MAXN]) 12 { 13 int lackL = min(C, W[N]-1); 14 for(int j = 0; j <=lackL; j++) DP[N][j] = 0; 15 for(int j = W[N]; j <=C; j++) DP[N][j] = V[N]; 16 for(int i = N - 1; i>=1; i--){ 17 lackL = min(C, W[i]-1); 18 for(int j = 0; j <=lackL; j++) DP[i][j] = DP[i+1][j]; 19 for(int j = W[i]; j <=C; j++){ 20 DP[i][j] = max( DP[i+1][j], DP[i+1][j-W[i]] + V[i] ); 21 } 22 } 23 return DP[1][C]; 24 } 25 26 int main() 27 { 28 int C, N; 29 cin >> C >> N; 30 for(int i = 1; i <=N; i++) { 31 cin >> W[i] >> V[i]; 32 } 33 cout<<knapsack(C, N, W, V, DP)<<endl; 34 35 return 0; 36 }
【拓展】
如果現在的物品重量weight和背包容量C都是正整數,那么當他們是實數時,如何改進算法滿足問題呢?
待完善(算法設計與分析P73)