Time Limit: 1 second
Memory Limit: 128 MB
【问题描述】
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
【样例解释】
选第一件物品1件和第三件物品2件。
【输入格式】
第一行:二个整数,V(背包容量,V<=200),N(物品数量,N<=30);
第2..N+1行:每行三个整数Wi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数
件,若为其他数字,则为此物品可购买的最多件数(Pi)。
【输出格式】
仅一行,一个数,表示最大总价值。
Sample Input
10 3 2 1 0 3 3 1 4 5 4
Sample Output
11
【题解】
遇到0的时候j层循环就从w[i]..m进行更新。
遇到不是0就从m..0进行循环。然后再嵌套一层k循环用来枚举放入几个物品。
一定要注意先用j循环再k循环,因为如果先k循环。会无法确定我们更新的值用了几个物品。会可能超过最大上限。
【代码】
#include <cstdio> int m,n,w[40],c[40],num[40],f[250]; void input_data() { scanf("%d%d",&m,&n); for (int i = 1;i <= n;i++) scanf("%d%d%d",&w[i],&c[i],&num[i]); } void get_ans() { for (int i = 1;i <= n;i++) //对n个物品进行决策 { if (num[i] == 0) //如果是完全背包 就要顺序更新 for (int j = w[i]; j <= m;j++) if (f[j] < f[j-w[i]] + c[i]) f[j] = f[j-w[i]] + c[i]; if (num[i] > 0) //如果是多重或01背包就逆序更新。 for (int j = m;j >=0;j--) for (int k = 1;k <= num[i];k++) //多重背包 { int ju = j-k*w[i]; //如果不能装下k个物品就跳过。 if (ju < 0) continue; if (f[j] < f[j-k*w[i]] + k *c[i]) //如果能更新解就更新。 f[j] = f[j-k*w[i]] + k * c[i]; } } } void output_ans() { printf("%d",f[m]); } int main() { //freopen("F:\rush.txt","r",stdin); input_data(); get_ans(); output_ans(); return 0; }