基础算法--贪心

0 阅读2分钟

贪心


贪心: 是用计算机来模拟一个“贪心”的人做出决策的过程。这个人十分贪婪,每一步行动总是按某种指标选取最优的操作。而且他目光短浅,总是只看眼前,并不考虑以后可能造成的影响。 贪心讲一个最优决策过程变成了一个多步决策过程,并在每步总是做出当前看来最好的选择。

现在,我们看到最值问题,有如下的几个思路:

  • 贪心
  • 二分(最小化最大值&最大化最小值)
  • 动态规划

下面我们来一起看一道题~

贪心算法.png

分析: 我们来看看这道题,想要花费最少的力气(最值!),我们就可以采取贪心的思想;每次都选取最小的两堆进行合并。那么想要查找最小的数量,我们如果用循环查找,按照数据设计是会超时的。我们如果使用堆排序,用时会大大降低(时间复杂度为O(log2(n)log_2(n)))。

那么我们要手写堆排序?当然不行...在C++的STL中已经包装好了优先队列容器(priority_queue),本质就是堆排序。在优先队列中,并不像普通队列一样先进先出,而是优先级高的先出,在本题中,最小的就是优先级最高的。

priority_queue<int> q; 默认大数优先级高
priority_queue<int, vector<int>, greater<int> > q; 这样是小数优先级高

下面是这道题的代码示例,可以看见用了STL的封装容器,代码简洁了不少:

#include <iostream>
#include <cmath>
#include <queue>
using namespace std;

int n;
long long ans, x, y;
priority_queue<long long, vector<long long>, greater<long long> > q;

int main(){
    cin >> n;
    for(int i = 1; i <= n; ++i){
        cin >> x;
        q.push(x);
    }
    for(int i = 1; i < n; ++i){
        x = q.top();
        q.pop();
        y = q.top();
        q.pop();
        ans += x + y;
        q.push(x + y);
    }

    cout << ans << endl;
}

再来看一道难一点的题目:

贪心算法-1.png

分析: 刚刚学习的贪心的读者,可能想着让第一只老鼠吃到最多的得分就好了。然而,这些奶酪给第二只老鼠吃,可能会得到更高的分数,所以这个思路行不通。 这道题的本质是,每块奶酪谁的得分最高就优先给谁吃。所以我们可以先把所有奶酪都给第二只老鼠,然后把两个数组相减,最后取前k大的奶酪给第一只老鼠吃即可。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int miceAndCheese(vector<int>& reward1, vector<int>& reward2, int k) {
    int n = reward1.size();
    vector<int> d(n);
    int ans = 0;
    for(int i =0; i < n; ++i){
        d[i] = reward1[i] - reward2[i];
        ans += reward2[i];
    }
    sort(d.begin(), d.end());
    for(int i = n - 1; i >= n - k; --i){
        ans += d[i];
    }
    return ans;
}

int main(){
    int n, k, x, ans;
    vector<int> r1;
    vector<int> r2;
    cin >> n >> k;
    for(int i = 1; i <= n; ++i){
        cin >> x;
        r1.push_back(x);
    }
    for(int i = 1; i <= n; ++i){
        cin >> x;
        r2.push_back(x);
    }
    ans = miceAndCheese(r1, r2, k);
    cout << ans << endl;

    return 0;
}