背包问题

Posted on 2015-07-22 01:11  指尖敲击流逝的岁月  阅读(177)  评论(0)    收藏  举报
题目和其他参考:

题目:
描述 小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N 元钱就行”。今天一早小明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N 元。于是,他把每件物品规定了一个重要度,分为5 等:用整数1~5 表示,第5 等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N 元(可以等于N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。设第j 件物品的价格为v[j],重要度为w[j],共选中了k 件物品,编号依次为j1...jk,则所求的总和为:v[j1]*w[j1]+..+v[jk]*w[jk]请你帮助金明设计一个满足要求的购物单。输入 第一行输入一个整数N(0 N m(其中N(<30000)表示总钱数,m(<25)为希望购买物品的个数。)
从第2 行到第m+1 行,第j 行给出了编号为j-1的物品的基本数据,每行有2 个非负整数
v p(其中v 表示该物品的价格(v≤10000),p 表示该物品的重要度(1~5)) 输出 每组测试数据输出只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的
最大值(<100000000)

分析:
对于不同物品的价格和不同物品的重要程度,心里有个权重,但是总价值不能超过ValueMax(最大容量,也就是背包问题中的容纳最大重量)。
现在有五件物品,总价值不能超过1000元。这五件物品的的单价和对应的重要程度的关系是:
800--2
400--5
300--5
400--3
200--2
问题是怎么在总价值的范围内买到最重要的物品,也就是多个物品的价格和重要程度的乘积的最大值。
由于每个物品的价格的不确定性,需要遍历在总价值范围内对应的每个权重值。
对于第一个物品填的时候没有问题。
在放第二个的时候,先要计算1000-400这个位置对应的值,然后加上第二个物品计算的权重值就是这个位置(价格)当前的权重值,然后和上一时刻存放在这个位置的值进行比较,将更新较大值在这个位置上。之后雷同。
具体地:
当遍历到第三个的时候:
1000-300 = 700->400*5=2000
(肯定能)塞进:2000+300*5 = 3500
更新(1000位置对应值)(通过判断当前值和上一时刻值的大小,保存较大值)
999-300 = 699->2000
(肯定能)塞进:2000+300*5 = 3500
更新(999位置对应值)(通过判断当前值和上一时刻值的大小,保存较大值)
。。。
300 -300 = 0->0
(肯定能)塞进:2000+300*5 = 3500
更新(300位置对应值)(通过判断当前值和上一时刻值的大小,保存较大值)
然后遍历第四个:
1000-400 = 600->x
x+400*3
更新(1000位置对应值)(通过判断当前值和上一时刻值的大小,保存较大值)
。。。。
===============================
代码设计思路:
for 1-5
    for 1000 - 当前物品的价格
        计算该遍历值对应权重值加上外循环对应的第几个物品乘以权重值
        判断计算的值和存放在遍历值对应的权重值,保存较大值
================================
代码有点挫,仅提供一个思路。
  1. #include "stdafx.h"
  2. #include "iostream"
  3. #include "string"
  4. #include <vector>
  5. using namespace std;
  6. /*
  7. 功能:
  8. 输入参数:int*p 指向二维数组的首地址,该二维数组第0行的两个数分别表示:总钱数<30000,和希望购买物品的个数<25;
  9. 该数组从第1行到第m行(1<=j<=m)中给出了编号为j的物品的基本数据,每行有2个非负整数,
  10. 表示该物品的价格(<=10000)和该物品的重要度(1~5)。
  11. GetResult表示不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。
  12. 不需做入参检查,测试用例可以保证~
  13. 例如:4000 8(第0行)
  14. 821 3 (第1行)
  15. 422 5
  16. 458 5
  17. 500 3
  18. 200 2
  19. 430 4
  20. 530 3
  21. 239 3
  22. 则表示 总钱数为4000,希望购买物品个数为8个,因此从第1行到第8行表示编号为j的物品的价格及物品的重要度。
  23. 返回值:无
  24. 温馨提示:根据题意可知,该二维数组只有两列,且行数为第0行的第二个元素数值+1;入参p不能按照二维数组的方法来取值,要将
  25. 二维的转换成一维的哦~
  26. */
  27. void GetResult(int*p,int& Get_Result)
  28. {
  29. vector <int>VecValue,VecImport,VecMoney;
  30. int num = *(p + 1);
  31. int money = *p;
  32. int *pstrTemp = p;
  33. int j = 2;
  34. int i;
  35. int value = 0;
  36. int maxvalue = 0;
  37. for (i = 0; i <= money;i++)
  38. {
  39. VecMoney.push_back(0);
  40. }
  41. for (i = 1; i <=num;i++)
  42. {
  43. VecValue.push_back(*(pstrTemp + j++));
  44. VecImport.push_back(*(pstrTemp + j++));
  45. }
  46. for (i = 0; i < num; i++)
  47. {
  48. for (j = money; j >= VecValue.at(i); j--)
  49. {
  50. value = VecMoney.at(j - VecValue.at(i)) + VecValue.at(i) * VecImport.at(i);
  51. if (value > VecMoney.at(j))
  52. {
  53. VecMoney.at(j) = value;
  54. }
  55. if (value > maxvalue)
  56. {
  57. maxvalue = value;
  58. }
  59. }
  60. }
  61. Get_Result = maxvalue;
  62. return ;
  63. }
  64. int main()
  65. {
  66. int p[6][2]={{1000,5},{800,2},{400,5},{300,5},{400,3},{200,2}};
  67. int get_result;
  68. GetResult(&p[0][0],get_result);
  69. cout<<get_result<<endl;
  70. return 0;
  71. }