考虑到每个主件最多只有两个附件,因此我们可以通过转化,把原问题转化为01背包问题来解决,在用01背包之前我们需要对输入数据进行处理,把每一种物品归类,即:把每一个主件和它的附件看作一类物品。处理好之后,我们就可以使用01背包算法了。在取某件物品时,我们只需要从以下四种方案中取最大的那种方案:只取主件、取主件+附件1、取主件+附件2、既主件+附件1+附件2。很容易得到如下状态转移方程:
f[i,j]=max{ f[i-1,j], f[i-1,j-v[i,0]]+v[i,0]*w[i,0], f[i-1,j-v[i,0]-v[i,1]]+v[i,0]*w[i,0]+v[i,1]*w[i,1], f[i-1,j-v[i,0]-v[i,2]]+v[i,0]*w[i,0]+v[i,2]*w[i,2],
f[i-1,j-v[i,0]-v[i,1]-v[i,2]]+v[i,0]*w[i,0]+v[i,1]*w[i,1]+v[i,2]*w[i,2]
}
其中,f[i,j]表示用j元钱,买前i类物品,所得的最大值,v[i,0]表示第i类物品主件的价格,v[i,1]表示第i类物品第1个附件的价格,v[i,2]表示第i类物品第2个附件的价格,w[i,0],w[i,1],w[i,2]分别表示主件、第1个附件和第2个附件的重要度。
【牛客网】例子:
主件 | 附件 |
电脑 | 打印机,扫描仪 |
书柜 | 图书 |
书桌 | 台灯,文具 |
工作椅 | 无 |
输入描述:
输入的第 1 行,为两个正整数,用一个空格隔开:N m
1 #include2 3 using namespace std; 4 5 6 int max(int a,int b) 7 { 8 return a>=b?a:b; 9 } 10 int main() 11 { 12 int money,num; 13 int value[61][3] = {0}; 14 int valueMutipWeight[61][3] = {0}; 15 int dp[61][3201] = {0}; 16 while(cin>>money>>num) 17 { 18 money /= 10; 19 int val,wei,lab; 20 for(int i = 1; i <= num; i++) 21 { 22 cin>>val>>wei>>lab; 23 wei = wei*val; 24 val /= 10; 25 26 if(lab == 0)//主件 27 { 28 value[i][lab] = val; 29 valueMutipWeight[i][lab] = wei; 30 } 31 else if(value[lab][1]==0)//第一个附件 32 { 33 value[lab][1] = val; 34 valueMutipWeight[lab][1] = wei; 35 } 36 else//第二个附件 37 { 38 value[lab][2] = val; 39 valueMutipWeight[lab][2] = wei; 40 } 41 } 42 43 44 for(int i = 1;i<=num;i++) 45 { 46 for(int j = 1;j <= money; j++) 47 { 48 dp[i][j] = dp[i-1][j]; 49 if(value[i][0]<=j)//只有主件 50 { 51 int t = max(dp[i-1][j],dp[i-1][j-value[i][0]]+valueMutipWeight[i][0]); 52 if(t>dp[i][j]) 53 dp[i][j] = t; 54 } 55 if(value[i][0]+value[i][1]<=j)//带第一个附件 56 { 57 int t = dp[i-1][j-value[i][0]-value[i][1]]+valueMutipWeight[i][0]+valueMutipWeight[i][1]; 58 if(t>dp[i][j]) 59 dp[i][j] = t; 60 } 61 if(value[i][0]+value[i][2]<=j)//带第二个附件 62 { 63 int t = dp[i-1][j-value[i][0]-value[i][2]]+valueMutipWeight[i][0]+valueMutipWeight[i][2]; 64 if(t>dp[i][j]) 65 dp[i][j] = t; 66 } 67 if(value[i][0]+value[i][1]+value[i][2]<=j)//带两个附件 68 { 69 int t = dp[i-1][j-value[i][0]-value[i][1]-value[i][2]]+valueMutipWeight[i][0]+valueMutipWeight[i][1]+valueMutipWeight[i][2]; 70 if(t>dp[i][j]) 71 dp[i][j] = t; 72 } 73 } 74 } 75 cout<<dp[num][money]; 76 } 77 78 return 0; 79 }
其中value[61][3] 记录60个物品的价格,if(laber == 0)是主件,将其价格写到value[i][0]的位置,value*weight 的值写到weight[i][0];if(laber == 1) 是第一个附件,将其价格写到第一列的位置上,value*weight 的值写到weight[i][1];laber==2同理。dp[num][money]表示用money这么多钱购买了第num-1件物品所获得的value*weight的最大值。
感谢:http://blog.csdn.net/liang5630/article/details/8030108