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;
}