当前位置:   article > 正文

贪心算法(基础)_贪心算法csdn

贪心算法csdn

目录

一、什么是贪心?

(一)以教室调度问题为例

1. 问题

2. 具体做法如下

3. 因此将在这间教室上如下三堂课 

4. 结论

(二)贪心算法介绍  

1. 贪心算法一般解题步骤

二、最优装载问题

(一)问题 

(二)分析 

(三) 核心代码 

(四)完整代码

三、完全背包问题 

(一)问题 

(二)分析  

(三)举例  

(四)核心代码 

(五)完整代码

(六)物品类的完整代码


一、什么是贪心?

(一)以教室调度问题为例

1. 问题

  • 假设有如下课程表,你希望将尽可能多的课程安排在某一间教室上

  

2. 具体做法如下

  • 第一步:选出结束最早的课,它就是要在这间教室上的第一堂课
  • 第二步:接下来,必须选择第一堂课结束后才开始的课。同样,选择开始最早的课,这将是要在这间教室上的第二堂课 

3. 因此将在这间教室上如下三堂课 

 

4. 结论

  •  这道题就采取的贪心算法===>每步都采取最优的做法

(二)贪心算法介绍  

  • 贪心算法又称贪婪算法,是指在对问题求解时,总是做出当前看来最好的选择,它不是从整体上加以考虑,所做出的仅是在某种意义上的局部最优解。而局部的最优解叠加在一起便是该问题整体的最优解,或者近似最优解。

1. 贪心算法一般解题步骤

  • 将问题分解为若干个子问题
  • 找出合适的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

二、最优装载问题

(一)问题 

  • 有一艘海盗船,载重量为C,每一件古董的重量为w_{i},海盗们如何尽可能的把多数量的宝贝装上海盗船 ?

(二)分析 

  1. 当载重量为定值的时候,w_{i}越小时,可装载的古董数量n越大,只要依次选择最小重量的古董即可
  2. 把n个古董的重量从小到大(非递减)排序,然后根据贪心策略尽可能多地选出前i个古董,直到不能继续装为止

(三) 核心代码 

  1. template<typename T1,typename T2,typename T3>
  2. void Loading(T1 c, vector<T2>& w, vector<T3>& t, vector<bool>& v)
  3. {
  4. //冒泡排序
  5. for (int i = w.size() - 1; i > 0; i--)//扫描次数
  6. {
  7. for (int j = 0; j < i; j++)
  8. {
  9. if (w[j] > w[j + 1])
  10. {
  11. swap(w[j], w[j + 1]);//交换物品重量
  12. swap(t[j], t[j + 1]);//交换物品的序号
  13. }
  14. }
  15. }
  16. for (int k = 0; w[k] <= c; k++)
  17. {
  18. v[k] = true;
  19. c = c - w[k];//船的剩余装载量
  20. }
  21. }

(四)完整代码

  1. #include<iostream>
  2. #include<vector>
  3. #include<stdbool.h>
  4. using namespace std;
  5. template<typename T1,typename T2,typename T3>
  6. void Loading(T1 c, vector<T2>& w, vector<T3>& t, vector<bool>& v)
  7. {
  8. //冒泡排序
  9. for (int i = w.size() - 1; i > 0; i--)//扫描次数
  10. {
  11. for (int j = 0; j < i; j++)
  12. {
  13. if (w[j] > w[j + 1])
  14. {
  15. swap(w[j], w[j + 1]);//交换物品重量
  16. swap(t[j], t[j + 1]);//交换物品的序号
  17. }
  18. }
  19. }
  20. for (int k = 0; w[k] <= c; k++)
  21. {
  22. v[k] = true;
  23. c = c - w[k];//船的剩余装载量
  24. }
  25. }
  26. int main()
  27. {
  28. float c;//表示船的最大载重和物品个数
  29. int n;//物品个数
  30. cout << "请依次输入船的最大载重和物品个数:" << endl;
  31. cin >> c >> n;
  32. vector<float> w(n);//存放物品的重量
  33. vector<int> t(n);;//存放物品的下标
  34. vector<bool> v(n);//记录物品是否装入船中
  35. cout << "请依次输入物品重量:" << endl;
  36. for (int i = 0; i < n; i++)//初始化物品信息
  37. {
  38. cin >> w[i];
  39. t[i] = i;
  40. v[i] = false;
  41. }
  42. Loading(c,w,t,v);
  43. cout << "装入了:" << endl;
  44. for (int i = 0; i < w.size(); i++)//输出装入的物品
  45. {
  46. if (v[i] == true)
  47. cout << t[i] << "号物品," << "重量为:" << w[i] << endl;
  48. }
  49. return 0;
  50. }
  51. //测试数据
  52. //30 8
  53. //4 10.5 7.8 4.9 5.1 3.3 4.6 3.2
  54. //结果
  55. //装入了:
  56. //7号物品,重量为:3.2
  57. //5号物品,重量为:3.3
  58. //0号物品,重量为:4
  59. //6号物品,重量为:4.6
  60. //3号物品,重量为:4.9
  61. //4号物品,重量为:5.1

三、完全背包问题 

(一)问题 

  • 有n件物品,每件物品有一定的重量w和相应的价值v,背包的最大容量为bagW,一种物品只能拿一样(不可重复拿),物品可以分割,求解将哪些物品装入背包里物品价值总和最大?

(二)分析  

  • 依照贪心策略,每次选取单位重量价值最大的物品,也就是说每次选择性价比(价值/重量)最高的物品,如果达到运载重量bagW,那么一定能得到价值最大

(三)举例  

 背包最大容量为30,在依次选择物品2、10、6、3、5后,背包最大价值达到69,背包剩余容量为30-(2+5+8+9+5)=1,只能装8号物品的\frac{1}{4},此时背包最大价值为69+\frac{1}{4}\times 6=70.5

(四)核心代码 

  1. void CompletePack(int _bagW,int n,struct goods*ps)
  2. {
  3. double sum = 0;//背包总价值
  4. for (int i = 0;i<n; i++)
  5. {
  6. if (_bagW >ps[i].w)//背包容量大于物品重量
  7. {
  8. ps[i].c = 1;
  9. sum =sum+ ps[i].v;
  10. _bagW = _bagW - ps[i].w;//剩余背包容量
  11. }
  12. else//背包容量小于物品重量
  13. {
  14. ps[i].c = (double)_bagW / (double)ps[i].w;//装入物品的比例(必须要强制转换)
  15. sum =sum+ps[i].c *ps[i].v;
  16. break;
  17. }
  18. }
  19. cout << "背包最大价值:" << sum << endl;
  20. }

(五)完整代码

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<iomanip>//setw的头文件
  4. using namespace std;
  5. #define MAX 100//物品数量最多为100
  6. struct goods
  7. {
  8. int n;//物品编号
  9. int w;//物品重量
  10. int v;//物品价值
  11. double p;//物品性价比
  12. double c;//记录装入物品的比例(如果物品完全放入背包,则c=1;不放入,c=0)
  13. }g[MAX];
  14. void Init(int n, struct goods*ps);//初始化物品信息
  15. bool cmp(struct goods a,struct goods b);//比较
  16. void CompletePack(int _bagW,int n,struct goods*ps);
  17. void print(int n, struct goods* ps);//遍历
  18. void Init(int n, struct goods*ps)//初始化物品信息
  19. {
  20. cout << "请依次输入物品的重量和价值:" << endl;
  21. for (int i = 0; i < n; i++)
  22. {
  23. ps[i].n = i;//物品编号
  24. cin >>ps[i].w >> ps[i].v;//初始化物品重量和价值
  25. ps[i].p = (double)ps[i].v / (double)ps[i].w;//性价比
  26. ps[i].c = 0;//都没有放入背包
  27. }
  28. }
  29. bool cmp(struct goods a,struct goods b)//比较
  30. {
  31. return a.p > b.p;//根据物品单位价值从大到小排序
  32. }
  33. void CompletePack(int _bagW,int n,struct goods*ps)
  34. {
  35. double sum = 0;//背包总价值
  36. for (int i = 0;i<n; i++)
  37. {
  38. if (_bagW >ps[i].w)//背包容量大于物品重量
  39. {
  40. ps[i].c = 1;
  41. sum =sum+ ps[i].v;
  42. _bagW = _bagW - ps[i].w;//剩余背包容量
  43. }
  44. else//背包容量小于物品重量
  45. {
  46. ps[i].c = (double)_bagW / (double)ps[i].w;//装入物品的比例(必须要强制转换)
  47. sum =sum+ps[i].c *ps[i].v;
  48. break;
  49. }
  50. }
  51. cout << "背包最大价值:" << sum << endl;
  52. }
  53. void print(int n, struct goods* ps)
  54. {
  55. for (int i = 0; i < n; i++)
  56. {
  57. if (ps[i].c != 0)
  58. {
  59. if (ps[i].c == 1)
  60. cout << "物品" << ps[i].n << setw(20) << "价值为:" << ps[i].v << endl;
  61. else
  62. cout << "物品" << ps[i].n << "装入了" << ps[i].c <<setw(8)<< " 价值为:" << ps[i].v << endl;
  63. }
  64. }
  65. }
  66. int main()
  67. {
  68. int bagW, n;//背包最大容量和物品数量
  69. cout << "请依次输入物品重量和物品数量:" << endl;
  70. cin >> bagW >> n;
  71. Init(n,g);//初始化物品信息
  72. cout << endl<<endl ;
  73. sort(g, g + n, cmp);//排序
  74. CompletePack(bagW,n, g);
  75. print(n, g);
  76. return 0;
  77. }
  78. //测试数据
  79. // 背包容量30 物品数量10
  80. //4 3
  81. //2 8
  82. //9 18
  83. //5 6
  84. //5 8
  85. //8 20
  86. //5 5
  87. //4 6
  88. //5 7
  89. //5 15
  90. //结果
  91. //背包最大价值:70.5
  92. //物品1 价值为:8
  93. //物品9 价值为:15
  94. //物品5 价值为:20
  95. //物品2 价值为:18
  96. //物品4 价值为:8
  97. //物品7装入了0.25 价值为:6

(六)物品类的完整代码

  1. #include<iostream>
  2. #include <iomanip>//setw的头文件
  3. using namespace std;
  4. #define MAX 20//物品数量最多为20
  5. class goods
  6. {
  7. private:
  8. int number;//物品编号
  9. int weight;//物品重量
  10. double value;//物品价值
  11. double percentage;//物品性价比
  12. double choice;//记录装入物品的比例(如果物品完全放入背包,则choice=1;不放入,choice=0)
  13. public:
  14. goods() { ; }
  15. goods(int _n,int _w, double _v, double _p, double _c)//构造函数
  16. {
  17. this->number = _n;
  18. this->weight = _w;
  19. this->value = _v;
  20. this->percentage = _p;
  21. this->choice = _c;
  22. }
  23. //~goods();//析构函数
  24. //获取私有成员
  25. int getn();//获取私有成员number
  26. int getw();//获取私有成员weight
  27. double getv();//获取私有成员value
  28. double getp();//获取私有成员percentage
  29. double getc();//获取私有成员choice
  30. //修改私有成员
  31. void setn(int _n);//修改私有成员的number
  32. void setw(int _w);
  33. void setv(double _v);
  34. void setp(double _p);
  35. void setc(double _c);
  36. };
  37. int goods::getn()
  38. {
  39. return number;
  40. }
  41. int goods::getw()//获取私有成员weight
  42. {
  43. return weight;
  44. }
  45. double goods::getv()
  46. {
  47. return value;
  48. }
  49. double goods::getp()
  50. {
  51. return percentage;
  52. }
  53. double goods::getc()
  54. {
  55. return choice;
  56. }
  57. void goods::setn(int _n)
  58. {
  59. number = _n;
  60. }
  61. void goods::setw(int _w)
  62. {
  63. weight = _w;
  64. }
  65. void goods::setv(double _v)
  66. {
  67. value = _v;
  68. }
  69. void goods::setp(double _p)
  70. {
  71. percentage = _p;
  72. }
  73. void goods::setc(double _c)
  74. {
  75. choice = _c;
  76. }
  77. int main()
  78. {
  79. int bagW, n;//背包最大容量和物品数量
  80. cout << "请依次输入背包容量和物品数量:" << endl;
  81. cin >> bagW >> n;
  82. //goods *g=new goods[MAX];
  83. goods g[MAX];
  84. cout << "请依次输入物品重量和物品价值:" << endl;
  85. for (int i = 0; i < n; i++)
  86. {
  87. int _n,_w,_c;//物品编号,物品重量,物品是否放入了背包
  88. double _v, _p;//物品价值,物品性价比
  89. cin >> _w >> _v;
  90. _p = _v / _w;//性价比
  91. _n = i;//编号
  92. _c = 0;//是否放入了背包
  93. goods gg(_n, _w, _v, _p, _c);
  94. g[i] = gg;
  95. }
  96. for (int i = 0; i <= n - 1; i++)//简单选择排序(按照性价比从大到小)
  97. {
  98. double max = g[i].getp();
  99. int k = i;//保存最大性价比的物品下标
  100. for (int j = i; j < n; j++)
  101. {
  102. if (max < g[j].getp())
  103. {
  104. max = g[j].getp();
  105. k = j;
  106. }
  107. }
  108. swap(g[i], g[k]);
  109. }
  110. double sum = 0;//背包总价值
  111. for (int i = 0; i < n; i++)
  112. {
  113. if (bagW > g[i].getw())//背包容量大于物品重量
  114. {
  115. g[i].setc(1);//物品全部装入背包
  116. sum += g[i].getv();//背包价值增加
  117. bagW = bagW - g[i].getw();//剩余背包容量
  118. }
  119. else//背包容量大于物品重量
  120. {
  121. double x = double(bagW) / double(g[i].getw());
  122. g[i].setc(x) ;//装入物品的比例
  123. sum += g[i].getc() * g[i].getv();
  124. break;
  125. }
  126. }
  127. cout << "物品的最大价值为:" << sum << endl;
  128. for (int i = 0; i < n; i++)
  129. {
  130. if (g[i].getc() != 0)
  131. {
  132. if (g[i].getc() == 1)
  133. cout << "物品" << g[i].getn() << setw(20) << "价值为:" << g[i].getv() << endl;
  134. else
  135. cout << "物品" << g[i].getn() << "装入了" << g[i].getc() <<setw(8)<< " 价值为:" << g[i].getv() << endl;
  136. }
  137. }
  138. return 0;
  139. }
  140. //测试数据
  141. //30 10
  142. //4 3
  143. //2 8
  144. //9 18
  145. //5 6
  146. //5 8
  147. //8 20
  148. //5 5
  149. //4 6
  150. //5 7
  151. //5 15
  152. //结果
  153. //物品的最大价值为:70.5
  154. //物品1 价值为:8
  155. //物品9 价值为:15
  156. //物品5 价值为:20
  157. //物品2 价值为:18
  158. //物品4 价值为:8
  159. //物品7装入了0.25 价值为:6

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/943317
推荐阅读
相关标签
  

闽ICP备14008679号