金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第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)。
分析:有依赖的背包,考虑到每个主件最多只有两个附件,因此我们可以通过转化,把原问题转化为01背包问题来解决,在用01背包之前我们需要对输入数据进行处理,把每一种物品归类,即:把每一个主件和它的附件看作一类物品。处理好之后,我们就可以使用01背包算法了。在取某件物品时,我们只需要从以下四种方案中取最大的那种方案:只取主件、取主件+附件1、取主件+附件2、既主件+附件1+附件2‘
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 6 using namespace std; 7 int dp[100][3200+10]; 8 int w[100][3],v[100][3]; 9 int main() 10 { 11 int n,m; 12 while(scanf("%d%d", &n, &m) != EOF) 13 { 14 int c,p,q; 15 n = n / 10; //都是10的整数,除以十,省空间 16 memset(w,-1,sizeof(w)); 17 for(int i = 1; i <= m; i++) 18 { 19 scanf("%d%d%d",&c,&p,&q); 20 c = c / 10; 21 if(q == 0) 22 { 23 w[i][q] = c; 24 v[i][q] = c * p; 25 } 26 else 27 { 28 if(w[q][1] == -1) 29 { 30 w[q][1] = c; 31 v[q][1] = c * p; 32 } 33 else 34 { 35 w[q][2] = c; 36 v[q][2] = c * p; 37 } 38 } 39 } 40 int t; 41 memset(dp, 0, sizeof(dp)); 42 for(int i = 1; i <= m; i++) 43 { 44 for(int j = 0; j <= n; j++) 45 { 46 dp[i][j] = dp[i - 1][j];//主件附件都不取 47 48 if(j >= w[i][0]) //取主件 49 { 50 t = dp[i - 1][j - w[i][0]] + v[i][0]; 51 if(t > dp[i][j]) 52 dp[i][j] = t; 53 } 54 if(j >= w[i][0] + w[i][1]) //取主件和附件1 55 { 56 t = dp[i - 1][j - w[i][0] - w[i][1]] + v[i][0] + v[i][1]; 57 if(t > dp[i][j]) 58 dp[i][j] = t; 59 } 60 if(j >= w[i][0] + w[i][2]) //取主件和附件2 61 { 62 t = dp[i - 1][j - w[i][0] - w[i][2]] + v[i][0] + v[i][2]; 63 if(t >= dp[i][j]) 64 dp[i][j] = t; 65 } 66 if(j >= w[i][0] + w[i][1] + w[i][2]) //取主件、附件1和附件2 67 { 68 t = dp[i - 1][j - w[i][0] - w[i][1] - w[i][2]] + v[i][0] + v[i][1] + v[i][2]; 69 if(t >= dp[i][j]) 70 dp[i][j] = t; 71 } 72 } 73 } 74 printf("%lld ",dp[m][n] * 10); 75 } 76 return 0; 77 }