[C++] 贪心算法之活动安排、背包问题

男娘i 2023-10-06 09:41 120阅读 0赞

一、贪心算法的基本思想

  在求解过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解。

  从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。

二、贪心算法的基本要素

  (1)最优子结构性质

  (2)贪心选择性质(局部最优选择)

三、贪心算法实例

  1、活动安排

  设有n个活动的集合 E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。

  每个活动 i 都有一个要求使用该资源的起始时间 si 和一个结束时间 fi,且 si < fi。如果选择了活动i,则它在半开时间区间 [si ,fi ) 内占用资源。若区间 [si , fi )与区间 [sj, fj ) 不相交,则称活动i与活动j是相容的。当 si ≥ fj 或 sj ≥ fi 时,活动 i 与活动 j 相容。

  活动安排问题就是在所给的活动集合中选出最大的相容活动子集合。

  例如:

format_png

  1. 1 #include <iostream>
  2. 2 using namespace std;
  3. 3
  4. 4 #define NUM 50
  5. 5
  6. 6 void GreedySelector(int n, int s[], int f[], bool b[])
  7. 7 {
  8. 8 b[1]=true; //默认将第一个活动先安排
  9. 9 int j=1; //记录最近一次加入b中的活动
  10. 10
  11. 11 //依次检查活动i是否与当前已选择的活动相容
  12. 12 for(int i=2;i<=n;i++)
  13. 13 {
  14. 14 if (s[i]>=f[j])
  15. 15 {
  16. 16 b[i]=true;
  17. 17 j=i;
  18. 18 }
  19. 19 else
  20. 20 b[i]=false;
  21. 21 }
  22. 22 }
  23. 23
  24. 24 int main()
  25. 25 {
  26. 26 int s[] = {
  27. 0,1,3,0,5,3,5,6,8,8,2,12}; //存储活动开始时间
  28. 27 int f[] = {
  29. 0,4,5,6,7,8,9,10,11,12,13,14}; //存储活动结束时间
  30. 28 bool b[NUM]; //存储被安排的活动编号
  31. 29 int n = (sizeof(s) / sizeof(s[0])) - 1;
  32. 30
  33. 31 GreedySelector(n, s, f, b);
  34. 32
  35. 33 for(int i = 1; i <= n; i++) //输出被安排的活动编号和它的开始时间和结束时间
  36. 34 {
  37. 35 if(b[i]) cout << "活动 " << i << " :" << "(" << s[i] << "," << f[i] << ")" <<endl;
  38. 36 }
  39. 37 return 0;
  40. 38 }

  2、背包问题

  给定一个载重量为 M 的背包,考虑 n 个物品,其中第 i 个物品的重量 wi(1 ≤ i ≤ n),价值 vi(1 ≤ i ≤ n),要求把物品装满背包,且使背包内的物品价值最大。
  有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为 0—1 背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。

  例如:

  有3种方法来选取物品:

    (1)当作 0—1 背包问题,用动态规划算法,获得最优值 220;
    (2)当作 0—1 背包问题,用贪心算法,按性价比从高到底顺序选取物品,获得最优值 160。由于物品不可分割,剩下的空间白白浪费。
    (3)当作背包问题,用贪心算法,按性价比从高到底的顺序选取物品,获得最优值 240。由于物品可以分割,剩下的空间装入物品 3 的一部分,而获得了更好的性能。

format_png 1

图2.1 背包问题

  1. 1 #include <iostream>
  2. 2 using namespace std;
  3. 3
  4. 4 #define NUM 50
  5. 5
  6. 6 //这里假设 w[], v[] 已按要求排好序
  7. 7 void Knapsack(int n,float M,float v[],float w[],float x[])
  8. 8 {
  9. 9 int i;
  10. 10 for(i = 1; i <= n; i++) x[i] = 0; //初始化数组
  11. 11 float c = M;
  12. 12 for(i = 1;i <= n; i++) //全部被装下的物品,且将 x[i] = 1
  13. 13 {
  14. 14 if(w[i]>c) break;
  15. 15 x[i] = 1;
  16. 16 c -= w[i];
  17. 17 }
  18. 18
  19. 19 if(i <= n) x[i] = c / w[i]; //将物品i 的部分装下
  20. 20 }
  21. 21
  22. 22 int main()
  23. 23 {
  24. 24 float M = 50; //背包所能容纳的重量
  25. 25 float w[] = {
  26. 0,10,20,30}; //这里给定的物品按价值降序排序
  27. 26 float v[] = {
  28. 0,60,100,120};
  29. 27 float x[NUM]; //存储每个物品装入背包的比例
  30. 28
  31. 29 int n = (sizeof(w) / sizeof(w[0])) - 1;
  32. 30
  33. 31 Knapsack(n, M, v, w, x);
  34. 32
  35. 33 for(int i = 1; i <= n; i++)
  36. 34 cout << "物品 " << i << " 装入的比例: " << x[i] << endl;
  37. 35 return 0;
  38. 36 }

发表评论

表情:
评论列表 (有 0 条评论,120人围观)

还没有评论,来说两句吧...

相关阅读

    相关 活动安排问题(贪心)

    活动安排问题(贪心) 有若干个活动,第i个开始时间和结束时间是\[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室? Input

    相关 贪心算法(1):活动安排问题

    题目 设有n个活动的集合E=\{1,2,…,n\},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源每个活动i都有一个要求使用该资源