博客
关于我
蓝桥杯AcWing学习笔记 7-1贪心的学习(上)(附相关蓝桥真题:付账问题、乘积最大)(Java)
阅读量:796 次
发布时间:2023-03-25

本文共 3585 字,大约阅读时间需要 11 分钟。

贪心算法与应用案例分析

贪心算法作为一类通用算法范式,广泛应用于多个领域。其核心思想是,在每一步做出局部最优的选择,以期望实现全局最优解。以下将从股票交易、仓库建址、钱数分配等多个问题入手,探讨贪心算法的应用及其效果。


一、股票交易中的贪心策略

在股票交易中,贪心策略的核心在于寻找相邻两天的收益率。如果后一天的价格高于前一天,则进行交易。这种策略的直观性使其成为初学者较为容易掌握的方法。

策略说明:

  • 将股票价格序列拆分为单日收益的交易。
  • 对于每一对相邻的股票价格,若后价格高于前,立即进行交易。
  • 这种方法简单直观,且能保证最优收益。
  • 案例分析:

    • 第一个样例:选择买入第二天,卖出第三天,获利4元,接着买入第四天,卖出第五天,获利3元,总利润7元。
    • 第二个样例:从第一天买入,第五天卖出,获利4元。虽然有其他交易策略(如买入第一天第三天,卖出第三天第五天),但贪心策略同样能获得4元收益。
    • 第三个样例:股票价格持续下跌,无法获利。贪心策略在此情况下表现良好。

    优化与证明: 贪心策略的正确性可以通过数学证明得出。任何跨度超过一天的交易都能拆分为一系列单日交易的组合。因此,贪心策略不仅简单,而且能保证最优收益。

    代码实现:

    import java.util.Scanner;
    public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) {
    a[i] = sc.nextInt();
    }
    int res = 0;
    for (int i = 0; i < n; i++) {
    if (a[i + 1] > a[i]) {
    res += a[i + 1] - a[i];
    }
    }
    System.out.print(res);
    }
    }

    二、仓库建址问题

    仓库建址问题的目标是将仓库建在使得各商店到仓库的距离之和最小的位置。

    问题分析:

  • 商店分布可能为奇数或偶数。
  • 当商店数量为奇数时,仓库建在中位数位置。
  • 当商店数量为偶数时,仓库建在中间两个商店的任意位置。
  • 数学证明: 根据均值不等式,仓库建在中位数位置时,距离和最小。对于奇数个商店,中位数位置到各点的距离之和最小;对于偶数个商店,中间位置的选择不影响总距离。

    代码实现:

    import java.util.Scanner;
    import java.util.Arrays;
    public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] x = new int[n];
    for (int i = 0; i < n; i++) {
    x[i] = sc.nextInt();
    }
    Arrays.sort(x);
    int c = x[n / 2];
    int res = 0;
    for (int i = 0; i < n; i++) {
    res += Math.abs(x[i] - c);
    }
    System.out.print(res);
    }
    }

    三、钱数分配问题

    在钱数分配问题中,目标是让钱数尽量集中,以减少标准差。均值不等式表明,标准差最小的分配方式是让各数尽可能接近平均值。

    数学证明: 根据均值不等式,标准差最小的条件是各数与平均值的差异最小。通过对钱数进行排序,逐步调整,使其接近平均值,能有效降低标准差。

    代码实现:

    import java.util.Arrays;
    import java.util.Scanner;
    public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    double s = sc.nextDouble();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) {
    a[i] = sc.nextInt();
    }
    Arrays.sort(a);
    double res = 0;
    double avg = s / n;
    for (int i = 0; i < n; i++) {
    double cur = s / (n - i);
    if (a[i] < cur) {
    cur = a[i];
    }
    res += Math.pow((cur - avg), 2) / n;
    s -= cur;
    }
    System.out.printf("%.4f", Math.sqrt(res));
    }
    }

    四、贪心与双指针的C++题

    在这道题中,我们需要从正数和负数中选出k个数,使得乘积的绝对值最大。

    策略说明:

  • k为偶数:从两边交替选数,尽量让乘积最大。
  • k为奇数:若所有数为负数,选最小的k个负数(乘积负);若有正数,选最大的正数,使乘积为正。
  • 代码实现:

    #include 
    #include
    #include
    using namespace std;
    int main() {
    int n = 100010;
    int k = 1000;
    vector
    a(n);
    // 初始化数据
    for (int i = 0; i < n; ++i) {
    a[i] = rand() % 100000;
    }
    sort(a.begin(), a.end());
    long long res = 1;
    int l = 0, r = n - 1;
    int sign = 1;
    if (k % 2 == 1) {
    res = a[r--];
    if (res < 0) sign = -1;
    }
    while (k > 0) {
    long long x = (long long)a[l] * a[l+1];
    long long y = (long long)a[r-1] * a[r];
    if (x * sign > y * sign) {
    res = (res * x) % MOD;
    l += 2;
    } else {
    res = (res * y) % MOD;
    r -= 2;
    }
    k -= 2;
    }
    cout << res << endl;
    return 0;
    }

    五、总结

    贪心算法在多个问题中展现了其独特的优势。通过合理的策略选择和数学证明,贪心策略不仅能够实现局部最优,更能在多个场景下达到全局最优。虽然在某些复杂问题中贪心算法可能无法达到最优,但在这些特定问题中,它提供了高效且易于实现的解决方案。

    转载地址:http://xzhfk.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现环形缓冲区(附完整源码)
    查看>>
    Objective-C实现生产者和消费者问题(附完整源码)
    查看>>
    Objective-C实现生产者消费者问题(附完整源码)
    查看>>
    Objective-C实现生成 Mandelbrot 曼德勃罗集图像算法 (附完整源码)
    查看>>
    Objective-C实现生成崩溃dump文件 (附完整源码)
    查看>>
    Objective-C实现生成数组的所有不同排列算法(附完整源码)
    查看>>
    Objective-C实现生成正态分布数据(附完整源码)
    查看>>
    Objective-C实现生成随机高斯分布(附完整源码)
    查看>>
    Objective-C实现用 PIL 改变对比度算法(附完整源码)
    查看>>
    Objective-C实现用二维数组实现矩阵的转置(附完整源码)
    查看>>
    Objective-C实现用半正弦公式计算两个坐标之间的距离算法 (附完整源码)
    查看>>