题目描述
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*为乘号)
请你帮助金明设计一个满足要求的购物单。
输入描述:
第1行,为两个正整数,用一个空格隔开:N m(其中N( < 32000 )表示总钱数,m( < 60 )为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数v p q(其中v表示该物品的价格(v < 10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)
输出描述:
输出一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。
示例1
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
2200
解答
带有附件的背包问题,它属于01背包的变式。
这题还好,每一个物品最多只有两个附件,那么我们在对主件进行背包的时候,决策就不再是两个了,而是五个。
还记得01背包的决策是什么吗?
1.不选,然后去考虑下一个
2.选,背包容量减掉那个重量,总值加上那个价值。
这个题的决策是五个,分别是:
1.不选,然后去考虑下一个
2.选且只选这个主件
3.选这个主件,并且选附件1
4.选这个主件,并且选附件2
5.选这个主件,并且选附件1和附件2.
这个。。。很好想吧。。。
我们知道,01背包的状态转移方程(已使用滚动数组优化)是),那么,这道题的转移方程也就不难写出了。
等等,你得先判断某个选附件的决策是不是可行的,如果当前的容量还够放第一个,或第二个,或两个都选的附件,那么才能考虑转移。
当然,不选附件的话就不用判啦,直接01背包的转移方程即可。
我们令数组表示某个主件的费用,而数组表示某个主件的价值。
同样的,用二维数组表示某个附件的费用,表示某个附件的价值,第二维只需要0,1,2这三个数,其中第二维是0的场合表示这个主件i的附件数量,它只能等于0或1或2。第二维是1或者是2的值代表以i为主件的附件1或者附件2的相关信息(费用 价值)。这些数组的信息应该在读入时处理好,具体详见代码。
这样,状态转移方程就是四个。
不选附件的①:;
选附件1的②:;
选附件2的③:;
选附件1和附件2的④:;
已经滚动掉了第一维,道理和正常向的01背包都是一样的,即只有i和i-1有关系,但是这个规律在循环中已经满足了所以完全没必要记录。
目标状态,输出就好。
参考代码:
#include <iostream> #define maxn 32005 using namespace std; int n,m; int v,p,q; int main_item_w[maxn]; int main_item_c[maxn]; int annex_item_w[maxn][3]; int annex_item_c[maxn][3]; int f[maxn]; int main(){ cin >> n >> m; for (int i=1;i<=m;i++){ cin >> v >> p >> q; if (!q){ main_item_w[i] = v; main_item_c[i] = v * p; } else{ annex_item_w[q][0]++; annex_item_w[q][annex_item_w[q][0]] = v; annex_item_c[q][annex_item_w[q][0]] = v * p; } } for (int i=1;i<=m;i++) for (int j=n;main_item_w[i]!=0 && j>=main_item_w[i];j--){ f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]); if (j >= main_item_w[i] + annex_item_w[i][1]) f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]); if (j >= main_item_w[i] + annex_item_w[i][2]) f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]); if (j >= main_item_w[i] + annex_item_w[i][1] + annex_item_w[i][2]) f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]); } cout << f[n] << endl; return 0; }