【6666】分组背包

来源:互联网 发布:数据库软件 中标 编辑:程序博客网 时间:2024/06/05 18:48
【问题描述】
一个旅行者有一个最多能装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;}


0 0