经典贪心算法模型

例题一

题目链接:https://ac.nowcoder.com/acm/contest/558/C

题意: 给定N个二元组(a1,b1),(a2,b2),…,(aN,bN),请你从中选出恰好K个,使得ai的最小值与bi的最小值之和最大。

请输出ai的最小值与bi的最小值之和

分析:我们可以先按b值从大到小排序,把二元组中的b值按从大到小的次序排序后,依次以第i = k,k + 1···n个数为最后一个数,那么最小的b值肯定是第i对二元组的b值,a值取最大的前k个数中最小的,这个过程可以用优先队列来完成。即在遍历过程中,如果队列的规模大于k,那么把a值最小的元素从队列中移除

参考代码

#include <stdio.h>
#include <queue>
#include <vector>
#include <algorithm>

using namespace std;

#define N 110000

struct Node {
    int a, b;
    bool operator < (const Node &u) const {
        return b > u.b;
    }
};

Node a[N];

int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i) scanf("%d%d", &a[i].a, &a[i].b);
    sort(a, a + n);
    int res = 0;
    priority_queue<int, vector<int>, greater<int> > q;
    for (int i = 0; i < n; ++i) {
        q.push(a[i].a);
        if (q.size() > k) q.pop();
        if (q.size() == k) res = max(res, q.top() + a[i].b);
    }
    printf("%d\n", res);
    return 0;
}

例题二

题目链接:http://poj.org/problem?id=3253

题意:给你n个长度为ai的木棒,假设把两个木棒i,j合成一个木棒的花费是ai + aj,问将n个木棒合成一个木棒的最小花费是多少

分析:这是一道特别经典的贪心问题,解决方案是将所有的木棒放入一个优先队列中去,依次取出最小的两根,合并后把新的木棒在放回到优先队列中去

参考代码

#include <stdio.h>
#include <queue>
#include <algorithm>
using namespace std;

#define N 20000

int x;

int main () {

    int n;
    while (scanf("%d",&n) == 1) {

        long long sum = 0;
        int cost = 0;
        priority_queue<long long, vector<long long>, greater<long long>  > q;
        for (int i = 0; i < n; ++i) {
            scanf("%d",&x);
            q.push(x);
        }

        while (q.size() >= 2) {
            long long x,y;
            x = q.top(); q.pop();
            y = q.top(); q.pop();
            sum += x + y;
            q.push(x + y);
        }

        printf("%lld\n",sum);
    }
    return 0;
}

例题三:题目链接 https://codeforces.com/problemset/problem/462/C

题意:给你n个整数还有一个初始化为0的得分,对于这n个数你首先把计算他们的和,并把和加到得分上,然后把这些数分成两堆,分别求和后加到得分上,如果某一堆只有一个元素那么计算完得分后这个堆就会消息,请你计算得分最大为多少

分析:这个题和上个题目有些类似,只需要每次把值最小的单独放到一个堆就行了,可以使用前缀和方便计算

参考代码

#include <stdio.h>
#include <algorithm>

using namespace std;

#define N 330000

typedef long long ll;

ll a[N], pre[N];

int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        pre[0] = 0;
        for (int i = 1; i <= n; ++i) scanf("%I64d", &a[i]); sort(a + 1, a + n + 1);
        for (int i = 1; i <= n; ++i) pre[i] = pre[i - 1] + a[i];
        ll res = 0;
        for (int i = 0; i < n; ++i) {
//            printf("%lld %lld\n", pre[n] - pre[i], a[i]);
            res += pre[n] - pre[i];
            res += a[i];
        }
        printf("%I64d\n", res);
    }
    return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值