• 贪心算法总结(未完结)


    贪心的定义(摘自百度百科)

    贪心算法(greedy algorithm,又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解

    贪心算法是以局部最优而达到全局最优,可以说贪心算法是短视的,每次只考虑当前状况下最好的选择。 

    贪心并没有通用的模板和算法思路,大多时候是靠刷题积累。


    区间问题

    AcWing 905. 区间选点

    思路分析: 

            1. 按照右端点从小到大将区间排序

            2. 依次从前往后枚举每个区间:

                    1 > 若当前区间能覆盖所选点,无需操作

                    2 > 若当前区间不能覆盖所选点,就选择当前区间的右端点作为新选的点,

                         同时答案要加一

    代码展示:
    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. struct Edge
    6. {
    7. int l, r;
    8. bool operator < (const Edge &W)const
    9. {
    10. return r < W.r;
    11. }
    12. }edges[N];
    13. int main()
    14. {
    15. int n;
    16. cin >> n;
    17. for (int i = 0; i < n; i ++)
    18. {
    19. int l, r;
    20. cin >> l >> r;
    21. edges[i] = {l, r};
    22. }
    23. sort(edges, edges + n);
    24. int res = 0, ed = -2e9;
    25. for (int i = 0; i < n; i ++)
    26. {
    27. if (edges[i].l > ed)
    28. {
    29. res ++;
    30. ed = edges[i].r;
    31. }
    32. }
    33. cout << res << endl;
    34. return 0;
    35. }

    AcWing 908. 最大不相交区间数量

    代码展示:
    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. struct Edge
    6. {
    7. int l, r;
    8. bool operator <(const Edge &W)const
    9. {
    10. return r < W.r;
    11. }
    12. }edges[N];
    13. int main()
    14. {
    15. int n;
    16. cin >> n;
    17. for (int i = 0; i < n; i ++)
    18. {
    19. int l, r;
    20. cin >> l >> r;
    21. edges[i] = {l, r};
    22. }
    23. sort(edges, edges + n);
    24. int res = 0, ed = -2e9;
    25. for (int i = 0; i < n; i ++)
    26. {
    27. if (edges[i].l > ed)
    28. {
    29. res ++;
    30. ed = edges[i].r;
    31. }
    32. }
    33. cout << res << endl;
    34. return 0;
    35. }

     AcWing 906. 区间分组  

    思路分析:

            1. 区间按照左端点从小到大排序

            2. 用小根堆去存储每组的右端点的最大值

            3. 从前往后处理每一个区间:

                    1 > 若当前区间的左端点小于堆顶,说明当前区间与前面所有组都存在交集,

                            那么就开一个新的组去存储当前区间

                    2 > 若当前区间的左端点大于堆顶,说明当前区间和堆顶无交集,

                          则可以将当前区间添加到堆顶所在组中,

                          即要更新该组在小根堆中存储的右端点数值

    代码展示: 
    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int N = 100010;
    6. //按照区间左端点大小排序
    7. struct Range
    8. {
    9. int l, r;
    10. bool operator <(const Range &W)const
    11. {
    12. return l < W.l;
    13. }
    14. }edges[N];
    15. int main()
    16. {
    17. int n;
    18. cin >> n;
    19. for (int i = 0; i < n; i ++)
    20. {
    21. int l, r;
    22. cin >> l >> r;
    23. edges[i] = {l, r};
    24. }
    25. sort(edges, edges + n);
    26. priority_queue<int, vector<int>, greater<int>> heap;
    27. for (int i = 0; i < n; i ++)
    28. {
    29. //当前枚举的区间
    30. auto t = edges[i];
    31. //当堆中为空或者与堆顶元素有交集
    32. if (heap.empty() || heap.top() >= t.l) heap.push(t.r);
    33. else
    34. {
    35. heap.pop();
    36. heap.push(t.r);
    37. }
    38. }
    39. cout << heap.size() << endl;
    40. return 0;
    41. }

    AcWing 907. 区间覆盖

    思路分析:

            1. 区间按照左端点从小到大排序

            2. 从前往后枚举每个区间(双指针算法)

                    每次选取能覆盖当前点st并且右端点最大的区间,然后更新st

    代码展示:
    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. struct Edge
    6. {
    7. int l, r;
    8. bool operator <(const Edge &W)const
    9. {
    10. return l < W.l;
    11. }
    12. }edges[N];
    13. int main()
    14. {
    15. int st, ed;
    16. cin >> st >> ed;
    17. int n;
    18. cin >> n;
    19. for (int i = 0; i < n; i ++)
    20. {
    21. int l, r;
    22. cin >> l >> r;
    23. edges[i] = {l, r};
    24. }
    25. sort(edges, edges + n);
    26. int res = 0;
    27. bool flag = false;
    28. //找到能覆盖当前点的最靠右的区间,更新当前点
    29. for (int i = 0; i < n; i ++)
    30. {
    31. int j = i, r = -2e9;
    32. while (j < n && st >= edges[j].l)
    33. {
    34. r = max(r, edges[j].r);
    35. j ++;
    36. }
    37. if (r < st)
    38. {
    39. res = -1;
    40. break;
    41. }
    42. res ++;
    43. if (r >= ed)
    44. {
    45. flag = true;
    46. break;
    47. }
    48. st = r;
    49. i = j - 1;
    50. }
    51. if (!flag) res = -1;
    52. cout << res << endl;
    53. return 0;
    54. }

     Huffman树

    哈夫曼树定义(摘自百度百科)

    给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

    哈夫曼树的构造 

    每次选取最小的两个数作为两个权值相加的节点的子节点,在将该节点与未选取的值再重复操作

    以一个样例来模拟这个过程:

    AcWing 148. 合并果子

     思路分析:

            用小根堆来存储权值,然后构造以哈夫曼树的思路得出最终结果

    代码展示:
    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. priority_queue<int, vector<int>, greater<int>> heap;
    6. int main()
    7. {
    8. int n;
    9. cin >> n;
    10. while (n --)
    11. {
    12. int x;
    13. cin >> x;
    14. heap.push(x);
    15. }
    16. int res = 0;
    17. while (heap.size() > 1)
    18. {
    19. int a = heap.top();
    20. heap.pop();
    21. int b = heap.top();
    22. heap.pop();
    23. res += (a + b);
    24. heap.push(a + b);
    25. }
    26. cout << res << endl;
    27. return 0;
    28. }

    排序不等式

    AcWing 913. 排队打水

    代码展示: 

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. typedef long long LL;
    6. int a[N];
    7. int main()
    8. {
    9. int n;
    10. cin >> n;
    11. for (int i = 0; i < n; i ++) cin >> a[i];
    12. sort(a, a + n);
    13. LL res = 0;
    14. for (int i = 0; i < n; i ++)
    15. res += a[i] * (n - i - 1);
    16. cout << res << endl;
    17. return 0;
    18. }

    绝对值不等式

    公式:

            | |a| - |b| | ≤ | a±b | ≤ |a| + |b|

     AcWing 104. 货仓选址

    代码展示:

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. int a[N];
    6. int main()
    7. {
    8. int n;
    9. cin >> n;
    10. for (int i = 0; i < n; i ++) cin >> a[i];
    11. sort(a, a + n);
    12. int res = 0;
    13. for (int i = 0; i < n; i ++)
    14. res += a[i] - a[i / 2];
    15. cout << res << endl;
    16. return 0;
    17. }


    推公式

    AcWing 125. 耍杂技的牛

    代码展示:

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 100010;
    5. typedef pair<int, int> PII;
    6. PII cow[N];
    7. int main()
    8. {
    9. int n;
    10. cin >> n;
    11. for (int i = 0; i < n; i ++)
    12. {
    13. int w, s;
    14. cin >> w >> s;
    15. cow[i] = {w + s, w};
    16. }
    17. sort(cow, cow + n);
    18. int res = -2e9, sum = 0;
    19. for (int i = 0; i < n; i ++)
    20. {
    21. int w = cow[i].second, s = cow[i].first - w;
    22. res = max(res, sum - s);
    23. sum += w;
    24. }
    25. cout << res << endl;
    26. return 0;
    27. }

  • 相关阅读:
    CSS3 就可以写出一个苹果官方渐变颜色文字效果,真的太逼真了!
    深入理解强化学习——多臂赌博机:乐观初始值
    leetCode 21.合并两个有序链表
    接口与抽象类的相同与不同
    机器学习---决策树的划分依据(熵、信息增益、信息增益率、基尼值和基尼指数)
    二叉树递归套路总结
    K8S之Pod详解
    Java框架(三)--Spring IoC容器与Bean管理(8)--基于Java Config配置IoC容器及Spring Test测试模块
    VMware Workstation安装ESXi和vCenter(8.0)
    Java JSON格式简介说明
  • 原文地址:https://blog.csdn.net/m0_73569492/article/details/134083581