題目
個物品,重量和價值分別存儲在數組和數組中,輸入總重量,求選出不超過的物品最大總價值。
每個物品只能選擇一次。
,均爲, 爲.
樣例輸入
4
2 1 3 2
3 2 4 2
5
個物品,重量分別是,價值分別是,揹包重量爲.
樣例輸出
7
選出號物品,剛好裝滿揹包,且總價值最大,爲.
算法1
表示從前個物品(號)中選出重量不超過的總價值。如果不選擇第個物品,則;如果選擇第個物品,則(不過要注意判斷,如果不成立說明揹包裝不下第個物品),這樣可得遞推關係:
其中初始值爲。
最終輸出。
由於要從更新到,所以複雜度爲。
代碼1
#include<stdio.h>
#include<math.h>
#define maxn 105
int max(int a, int b){
return (a>b)?a:b;
}
int main(){
int n, W;
int w[maxn], v[maxn];
int dp[maxn][maxn];
while(scanf("%d %d", &n, &W)==2){
for(int i = 1;i <= n;i++){
scanf("%d", w + i);
}
for(int i = 1;i <= n;i++){
scanf("%d", v + i);
}
for(int j = 0;j <= W;j++){
dp[0][j] = 0;
}
for(int i = 1;i <= n;i++){
dp[i][0] = 0;
}
for(int i = 1;i <= n;i++){
for(int j = 1;j <= W;j++){
if(w[i]>j)dp[i][j] = dp[i-1][j];
else
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);
}
}
printf("%d\n", dp[n][W]);
}
return 0;
}
算法2
如果改變題目對輸入數據的約束:
,均爲, 爲,爲.
已知複雜度爲,而上述W非常大,這會導致複雜度很高。
不妨改變爲前個物品(號)中選出價值爲的最小重量,則需要從更新到,然後輸出滿足的的最大值。所有物品的總價值不會超過,複雜度就降下來了。
如果不選擇第i個物品,則dp[i][j]對應從前個物品中選出價值爲,即;如果選擇第個物品,則對應(記得先判斷),這樣得到遞推關係:
初始值爲,。輸出滿足的的最大值。
#include<stdio.h>
#define maxn 105
#define INF 1000000005 // 所有物品總重最多爲10億
#define maxv 105
int min(int a, int b){
return (a<b)?a:b;
}
int main(){
int n, W;
int v[maxn], w[maxn];
int dp[maxn][maxn * maxv];
int totalvalue, res;
while(scanf("%d", &n)==1){
for(int i = 0;i < n;i++){
scanf("%d", &w[i]);
}
totalvalue = 0;
for(int i = 0;i < n;i++){
scanf("%d", &v[i]);
totalvalue += v[i];
}
scanf("%d", & W);
for(int j = 1;j <= totalvalue;j++){
dp[0][j] = INF;
}
dp[0][0] = 0;
for(int i = 1;i <= n;i++){
for(int j = 0;j <= totalvalue;j++){
if(j>=v[i-1]){
dp[i][j] = min(dp[i-1][j],dp[i-1][j-v[i-1]]+w[i-1]);
}
else dp[i][j] = dp[i-1][j];
}
}
// 輸出dp[n][j]中不超過W的最大的j
res = 0;
for(int j = totalvalue;j >= 0;j--){
if(dp[n][j]<=W){
res = j;
break;
}
}
printf("%d\n", res);
}
return 0;
}