Leetcode学习之贪心算法(3)

开宗明义:本系列基于小象学院林沐老师课程《面试算法 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
题目描述已知在一个平面上有一定数量的气球,平面可以看作成一个坐标系,在平面的x轴的不同位置安排弓箭手向y轴方向射箭,弓箭可以向y轴走无穷远;给定气球的宽度为: x s t a r t < = x < = x e n d x_{start}<=x<=x_{end} ,问至少需要多少弓箭手,可以将气球全部打爆
在这里插入图片描述
思路
在这里插入图片描述
步骤
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试代码

#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
题目描述已知一条公路上,有一个起点与一个终点,这之间有 n n 个加油站;已知从这 n n 个加油站到终点的距离 d d 与各个加油站可以加油的量 I I ,起点位置至终点的距离 L L 与起始时刻油箱中的汽油量 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;
}