什么是贪心
贪心:贪心在解决问题上是目光短浅的,仅仅根据当前的已知信息就做出选择,并且一旦做了选择,就不再更改
常见的贪心问题
- 区间问题
- Huffman树
- 排序不等式
- 绝对值不等式
- 推公式
区间问题
区间覆盖
典型题例:
给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 −1。
示例 :
输入:第一行包含两个整数 s 和 t,表示给定线段区间的两个端点。
第二行包含整数 N,表示给定区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
1 5
3
-1 3
2 4
3 5
输出:
2
思路:左端点排序 + 贪心决策
-
将所有区间按照左端点从小到大进行排序
-
从前往后枚举每个区间,在所有能覆盖start的区间中,选择右端点的最大区间,然后将start更新成右端点的最大值(贪心决策);
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range{
int l, r;
bool operator< (const Range&w) const {
return l < w.l;
}
} ranges[N];
int main() {
int st, ed;
scanf("%d%d", &st, &ed);
scanf("%d", &n);
for (int i = 0; i < n; i ++) {
int l, r;
scanf("%d%d", &l, &r);
ranges[i] = {l, r};
}
sort(ranges, ranges + n);
int ans = 0;
bool success = false;
for (int i= 0; i < n; i ++) {
int j = i, r = -2e9;
while (j < n && ranges[j].l <= st) { //找到所有左端点<=st的区间右端点最大的点
r = max(r, ranges[j].r);
j ++;
}
if (r < st) { //肯定有空隙
ans = -1;
break;
}
ans ++;
if (r >= ed) {
success = true;
break;
}
st = r; //更新st
i = j - 1; //
}
if (!success) ans = -1;
printf("%d", ans);
}
Huffman树
合并果子
典型题例:
在一个果园里,达达已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。达达决定把所有的果子合成一堆。每一次合并,达达可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。
可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。达达在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以达达在合并果子时要尽可能地节省体力。
假定每个果子重量都为 1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使达达耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1,2,9。可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3。
接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。
所以达达总共耗费体力=3+12=15。
可以证明 15 为最小的体力耗费值。
示例 :
输入:输入包括两行,第一行是一个整数 n,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 种果子的数目。。
3
1 2 9
输出:
15
思路
- 使用小根堆维护所有果子,每次弹出堆顶的两堆果子,并将其合并,合并之后将两堆重量之和再次插入小根堆中。
代码:
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n;
int main() {
scanf("%d", &n);
priority_queue<int, vector<int>, greater<int>> heap; //小根堆
for (int i = 0; i < n; i ++) {
int x;
cin >> x;
heap.push(x);
}
int ans = 0;
while (heap.size() > 1) { //堆的个数大于1就需要合并
int a = heap.top(); heap.pop();
int b = heap.top(); heap.pop();
ans += a + b;
heap.push(a + b);
}
printf("%d", ans);
return 0;
}
充电站
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习