-
1、区间选点(最大不相交区间数量)(区间合并)
- 与之前不同的是脑子里可以有最优解的模型
- 以上三个问题对应到贪心上面都是一个问题
- 对于贪心问题的证明,只要证明子区间改变顺序前后的答案不会更优,这样的整体区间就是最优的,以部分最优推到整体最优,看似目光短浅,但是可以证明他的正确性
- 证明贪心解>=最优解(显而易见)
- 问题是如何证明贪心解<=最优解
- 像区间选点问题,先按照右端点排序要是假如有一个逆序右端点,贪心解会变少,但不是最优解,所以按右端点排序的贪心就是最优解
- 代码
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> PP;
const int N=1e5+10;
#define f first
#define s second
PP node[N];
bool cmp(PP a,PP b)
{
return a.s<b.s;
}
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
cin>>node[i].f>>node[i].s;
}
sort(node,node+n,cmp);
int res=0,end=-0x3f3f3f3f;
for(int i=0;i<n;i++)
{
if(node[i].f>end)
{
res++;
end=node[i].s;
}
}
cout<<res<<endl;
return 0;
}
-
2、区间分组
- 按照左端点排序依次枚举,不想证明,脑子里有模型就好了
- 有冲突就重新分组,没有冲突就把他放到堆中删掉原堆顶,加上现有的右端点
- 代码
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
struct Node
{
int l,r;
bool operator <(const Node &w)const
{
return l<w.l;
}
}node[N];
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
node[i]={l,r};
}
sort(node,node+n);
priority_queue<int,vector<int>,greater<int>>heap;
for(int i=0;i<n;i++)
{
Node g=node[i];
if(heap.empty()||heap.top()>=g.l)heap.push(g.r);
else
{
int t=heap.top();
heap.pop();
heap.push(g.r);
}
}
printf("%d\n",heap.size());
return 0;
}
-
3、区间覆盖
- 依旧按照左端点排序,拿到符合要求的左端点中右端点最大的就是满足条件的最优解,部分最优得到整体最优
- 代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct Node
{
int l,r;
bool operator<(const Node &w)const
{
return l<w.l;
}
}node[N];
int main()
{
int start,end;
cin>>start>>end;
int n;cin>>n;
for(int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
node[i]={l,r};
}
sort(node,node+n);
int res=0;
int flag=0;
for(int i=0;i<n;i++)
{
int j=i,r=-0x3f3f3f3f;
while(j<n && node[j].l<=start)
{
r=max(r,node[j].r);
j++;
}
if(r<start)
{
res=-1;
break;
}
res++;
if(r>=end)
{
flag=1;
break;
}
start=r;
i=j-1;
}
if(!flag)res=-1;
cout<<res<<endl;
return 0;
}