前言
区间贪心问题解法正确的证明方法:为了证明真实解ans
=解法求得的解cnt
,可以利用两边夹逼的思想(证明ans<=cnt
同时证明ans>=cnt
),这两个条件前一个靠定义证明,后一个靠构造极限情况或者反证法证明。还有一种证明思路是:证明真实解可以通过等价变换变化到解法算出的解(即所求最值没有发生变化)。
一、题目陈述
二、解决思路
1.排序
将区间按照起始端点从小到大的顺序排序。
2.遍历贪心
从前往后遍历所有区间,在所有起始端点小于起点st
的区间中,选择终止端点最大的区间进行覆盖操作。
3.双指针算法
使用双指针算法将遍历操作的时间复杂度维持在O(n)
。
三、代码实现
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
int n;
struct Seg{
int s,e;
bool operator< (const Seg &W) const {
return s<W.s;
}
}segs[N];
int main() {
int st,ed;
cin>>st>>ed;
cin>>n;
for(int i=0;i<n;i++) {
cin>>segs[i].s>>segs[i].e;
}
sort(segs,segs+n);
int res = 0;
bool success = false;
for(int i=0;i<n;i++) {
// 双指针算法的经典写法
int j=i;
int r=-2e9;
while(j<n&&segs[j].s<=st) {
r = max(r,segs[j].e);
j++;
}
if(r<st) {
res = -1;
break;
}
res ++;
if(r>=ed) {
success = true;
break;
}
// 更新起点
st = r;
// 更新i指针 变成j-1后经过i++,i指针就恢复为j,因为segs[j].s不满足<=st,但是segs[j]可能满足下一次迭代的条件
i=j-1;
}
if(!success) res = -1;
cout<<res<<endl;
return 0;
}
总结
这道贪心题排序是比较好想的,所有起始端点覆盖起点的区间中选择终止端点最大的区间也是容易理解的。重点在于双指针算法中对i指针
更新的想法和写法。