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;
}