开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!
Leetcode学习之贪心算法(3)
1、射击气球(排序、贪心) Leetcode 452.
题目来源:
L
e
e
t
c
o
d
e
452.
M
i
n
i
m
u
m
N
u
m
b
e
r
o
f
A
r
r
o
w
s
t
o
B
u
r
s
t
B
a
l
l
o
o
n
s
Leetcode \ 452.\ Minimum \ Number \ of \ Arrows \ to \ Burst \ Balloons
Leetcode 452. Minimum Number of Arrows to Burst Balloons
题目描述:已知在一个平面上有一定数量的气球,平面可以看作成一个坐标系,在平面的x轴的不同位置安排弓箭手向y轴方向射箭,弓箭可以向y轴走无穷远;给定气球的宽度为:
x
s
t
a
r
t
<
=
x
<
=
x
e
n
d
x_{start}<=x<=x_{end}
xstart<=x<=xend,问至少需要多少弓箭手,可以将气球全部打爆?
思路:
步骤:
测试代码:
#include <algorithm>
#include <vector>
using namespace std;
bool cmp(const pair<int, int>&a, const pair<int, int>&b) {
return a.first < b.first;//无需考虑左端点相同时的排序
}
class Solution {
public:
int findMinArrowShots(vector<pair<int, int>>& points) {
if (points.size() == 0) {
return 0;//传入的数据可能为空,直接返回0
}
sort(points.begin(), points.end(), cmp);//对气球按照左端点从小到大进行排序
int shoot_num = 1;
int shoot_begin = points[0].first;//初始化弓箭手数量为1
int shoot_end = points[0].second;//初始化射击区间,即为第一个气球的两端点
for (int i = 1; i < points.size(); i++) {
if (points[i].first < shoot_end) {
shoot_begin = points[i].first;
if (shoot_end > points[i].second) {
shoot_end = points[i].second;
}
}
else
{
shoot_num++;
shoot_begin = points[i].first;//再保证气球呗射穿的情况下,射击区间不再更新,增加一个射击区间
shoot_end = points[i].second;
}
}
return shoot_num;
}
};
int main() {
vector<pair<int, int>> points;
points.push_back(make_pair(10, 16));
points.push_back(make_pair(2, 8));
points.push_back(make_pair(1, 6));
points.push_back(make_pair(7, 12));
Solution solve;
printf("%d\n", solve.findMinArrowShots(points));
system("pause");
return 0;
}
效果图:
2、最优加油方法(最大堆、贪心) poj 2431 Expedition
题目来源:
p
o
j
2431.
E
x
p
e
d
i
t
i
o
n
poj \ 2431. \ Expedition
poj 2431. Expedition
题目描述:已知一条公路上,有一个起点与一个终点,这之间有
n
n
n个加油站;已知从这
n
n
n个加油站到终点的距离
d
d
d与各个加油站可以加油的量
I
I
I,起点位置至终点的距离
L
L
L与起始时刻油箱中的汽油量
P
P
P;假设使用1个单位的汽油即走了1个单位的距离,油箱中没有上限,最少加几次油,可以从起点开至终点?如果无法到达终点,返回-1。
分析:
思路:
测试代码:
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
bool cmp(const pair<int, int> &a, const pair<int, int> &b) {
return a.first > b.first;
}
int get_minimum_stop(int L, int P, vector<pair<int, int>> &stop) {//L为起点到终点的距离,P为起点初始的汽油量,pair<该加油站到终点的距离、加油站汽油量>
priority_queue<int> Q;//存储油量的最大堆
int result = 0;//记录加过几次油的变量
stop.push_back(make_pair(0, 0));//将终点作为一个停靠点,添加至stop数组。最后一个点
sort(stop.begin(),stop.end(), cmp);//将以停靠点至终点的距离从大到小进行排序,因为题目中的顺序是乱给的
for (int i = 0; i < stop.size(); i++) {//遍历各个停靠点
int dis = L - stop[i].first;//当前要走的距离:即为当前距离距终点的距离L减去下一个停靠点至终点的距离
while ( dis > P && !Q.empty())
{
P += Q.top();//加油
Q.pop();
result++;
}
if (Q.empty() && P < dis) {
return -1;
}
P = P - dis;
L = stop[i].first;//停靠点至终点的距离
Q.push(stop[i].second);//更新L为当前停靠点至终点距离
}//将当前停靠点的汽油量添加至最大堆
return result;
}
int main() {
vector<pair<int, int>>stop;
int N=4, L, P, distance, fuel;
for (int i = 0; i < N; i++) {
scanf("%d %d", &distance, &fuel);
stop.push_back(make_pair(distance, fuel));
}
scanf("%d %d", &L, &P);
printf("%d\n", get_minimum_stop(L, P, stop));
system("pause");
return 0;
}