一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,···,Wn,它们的价值分别是C1,C2,···,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
【输入格式】
第1行:三个整数,V(背包容量,V<=200),n(物品数量,N<=30)和T(最大组号,T <= 10);
第2至N+1行:每行三个整数Wi,Ci,P,表示每个物品的重量、价值、所属组号。
【输出格式】
仅一行,一个数,表示最大总价值。
【输入样例】
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
【输出样例】
20
【题解】
对于每一个组而言,只有选其中一个或者全不选。
枚举每一组,然后枚举容量,最后枚举该组中的所有物品。这样可以做到每组中的物品只会被选一次。
这里和0/1背包的差别就是,0/1背包是枚举单个物品,对单个物品都进行考虑是否要拿。而分组背包,则是在组的前提下,对每个组内的物品进行决策,就是说把每个物品都放一下看看在j容量时,哪一个更优。
f[j]表示容积不超过j时,物品所能获得的最大收益。
【代码】
#include <cstdio> #include <cstring> int v,n,t,w[50],c[50],a[15][50],f[250]; void input_data() { scanf("%d%d%d",&v,&n,&t); for (int i = 1;i <= n;i++) { int p; scanf("%d%d%d",&w[i],&c[i],&p); a[p][++a[p][0]] = i; //把这个物品存在p组的a[p][0]位置.a[p][0]用于存储物品p组物品个数. } } void get_ans() { memset(f,0,sizeof(f)); for (int i = 1;i <= t;i++) //枚举组 for (int j = v;j >=0;j--) //枚举背包的容量 for (int k = 1;k <= a[i][0];k++) //枚举该组内的所有物品 if (j-w[a[i][k]] >=0) //如果能够装的下 { if (f[j] < f[j-w[a[i][k]]]+c[a[i][k]]) //尝试用该物品更新该容积下的最优值 f[j] = f[j-w[a[i][k]]] + c[a[i][k]]; } } void output_ans() { printf("%d",f[v]); } int main() { //freopen("F:\rush.txt","r",stdin); input_data(); get_ans(); output_ans(); return 0; }