贪心问题
1.防晒
题目链接:https://www.acwing.com/problem/content/112/ (算法竞赛进阶指南)
思路:将所有牛所需要的区间排序,从后向前一次为牛选择防晒霜。当一个防晒霜可以同时满足两头牛的时候,优先满足靠后的区间,因为前面牛可能有前面的防晒霜来满足。
代码:
#include <cstring> #include <iostream> #include <algorithm> #include <map> using namespace std; typedef pair<int, int> PII; const int N = 2510; int n, m; PII cows[N]; int main() { cin >> n >> m; for(int i = 0; i < n; i++) { cin >> cows[i].first >> cows[i].second; } sort(cows, cows + n); map<int, int> spfs; for(int i = 0; i < m; i++) { int spf, cover; cin >> spf >> cover; spfs[spf] += cover; } int res = 0; //解决边界条件 spfs[0] = spfs[1001] = n; for(int i = n - 1; i >= 0; i--) { auto cow = cows[i]; //找到第一个大于当前奶牛需要的右边界的防晒霜,向前减之后得到最后一个小于等于右边界的值 auto it = spfs.upper_bound(cow.second); it -- ; //判断当前的防晒霜是否可以满足条件 if(it -> first >= cow.first && it -> first <= cow.second) { res++; if(--it -> second == 0) spfs.erase(it); } } cout << res << endl; return 0; }
2.畜栏预定
题目链接:https://www.acwing.com/problem/content/113/(算法竞赛进阶指南)
思路:维护遍历到的所有牛的右区间的最小值,当前如果有新牛加入时,如果新牛的左端点和最小值没有重合那么就可以加入到当前这组牛中,更新这组牛新的最右区间最小值。
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef pair<int, int> PII; const int N = 50010; int n; pair<PII,int> cows[N]; int id[N]; int main() { cin >> n; for(int i = 0; i < n; i++) { cin >> cows[i].first.first >> cows[i].first.second; cows[i].second = i; } sort(cows, cows + n); //将牛按照左端点排序 priority_queue<PII, vector<PII>, greater<PII>> heap; for(int i = 0; i < n; i++) { auto cow = cows[i].first; //新遍历到的牛的左端点如果和当前的遍历到的牛的右端点最小值右相交, //那么和其他牛也一定有相交,这样只能加入一个新的畜栏 if(heap.empty() || heap.top().first >= cow.first) { PII stall = {cow.second, heap.size() + 1}; id[cows[i].second] = stall.second; heap.push(stall); } else //如果和当前的右边最小值不相交,那么必然可以添加到当前这组牛中, //更新这组牛的最右边界后再次加入优先队列 //如果当前牛可以加入到右端点值最小的那一组牛中,不一定可以加入到其他的组中, //但是如果可以加入到其他组中,也必然可以加入到最小的那一组中,因为优先队列维护各组的右端点值递增 { auto stall = heap.top(); heap.pop(); stall.first = cow.second; id[cows[i].second] = stall.second; heap.push(stall); } } cout << heap.size() << endl; for(int i = 0; i < n; i++) cout << id[i] << endl; return 0; }
3.雷达设备
题目链接:https://www.acwing.com/problem/content/114/(算法竞赛进阶指南)
思路:将小岛映射成线段,找线段有多少完全不相交就需要多少的雷达
代码:
#include <iostream> #include <algorithm> #include <cmath> using namespace std; typedef pair<double, double> PDD; const int N = 1010; const double eps = 1e-6, INF = 1e10; int n, r; PDD segs[N]; int main() { bool success = true; cin >> n >> r; for(int i = 0; i < n; i++) { int x, y; cin >> x >> y; if(y > r) { success = false; break; } double len = sqrt(r * r - y * y); segs[i] = {x + len, x - len}; } if(!success) cout << -1 << endl; else { sort(segs, segs + n); int res = 0; double last = -INF; for(int i = 0; i < n; i++) { auto seg = segs[i]; //后面的起点和后面的终点之间不相交 if(seg.second > last + eps) { res++; last = seg.first; } } cout << res << endl; } return 0; }
4.Minimum Number of Arrows to Burst Balloons
题目链接:https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/ (Leetcode)
思路:同上一题
代码:
class Solution { public: static bool mycompare(vector<int>&a,vector<int>&b) { //先按照结尾降序排序,再按照开头降序排序 if(a[1]==b[1]) return a[0]<b[0]; return a[1]<b[1]; } int findMinArrowShots(vector<vector<int>>& points) { if(points.size()==0) return 0; sort(points.begin(),points.end(),mycompare); int arrows=0; int lastend=INT_MIN; for(int i=0;i<points.size();i++) { //当后面的段的开始位置大于当前结束的位置的时候,需要增加新的段 if(lastend==INT_MIN||points[i][0]>lastend) { arrows++; lastend=points[i][1]; } } return arrows; } };
5.Non-overlapping Intervals
题目链接:https://leetcode.com/problems/non-overlapping-intervals/(Leetcode)
思路:同上一题
代码:
class Solution { public: static bool cmp(vector<int> a, vector<int> b) { if(a[0] == b[0]) return a[1] > b[1]; else return a[0] < b[0]; } int eraseOverlapIntervals(vector<vector<int>>& intervals) { if(intervals.size() == 0 || intervals[0].size() == 0) return 0; sort(intervals.begin(), intervals.end(), cmp); int cnt = 0; int th = intervals[0][1]; for(int i = 1; i < intervals.size(); i++) { if(intervals[i][0] < th) { cnt ++; th = min(th, intervals[i][1]); } else th = intervals[i][1]; } return cnt; } };
6.Maximum Length of Pair Chain
题目链接:https://leetcode.com/problems/maximum-length-of-pair-chain/(Leetcode)
思路:按照右端点进行排序,如果遍历出当前元素的左端点和前一个的右端点没有相交,那么就合并,因为右端点是从小到大进行排序,因此合并以后也依然比后面的右端点的值要小。
class Solution { public: int findLongestChain(vector<vector<int>>& pairs) { // sort by the second value sort(pairs.begin(), pairs.end(), [] (auto &left, auto &right) { return left[1] < right[1]; }); int count = 0, last = INT_MIN; for (auto p : pairs) { if (p[0] > last) { count++; last = p[1]; } } return count; } };

浙公网安备 33010602011771号