算法提高 线段和点
时间限制:1.0s 内存限制:256.0MB
提交此题
问题描述
有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a>=b且a<=c,称点a满足区间[b,c]。
求最小的点的子集,使得所有区间都被满足。
输入格式
第一行两个整数n m
以下n行 每行一个整数,代表点的坐标
以下m行 每行两个整数,代表区间的范围
输出格式
输出一行,最少的满足所有区间的点数,如无解输出-1。
样例输入
5 5
2
6
3
8
7
2 5
3 4
3 3
2 7
6 9
样例输出
2
数据规模和约定
1<=n,m<=10000
0<=点和区间的坐标<=50000
http://lx.lanqiao.cn/problem.page?gpid=T367
首先将区间起点按照从小到大排序 然后终点也是按照从小到大排序
用一个cmp实现。
之后 用l 和 r 记录 区间叠加的时候的重复区间的大小
用队列记录符合l和r的点的个数
当队列里所有元素都不符合l和r 的时候 那么 就是证明这个新的区间和上面的区间没有重复可用的点了。
这个时候就让点数加1即可
最后 定义两个极限大的哨兵,起到记录最后一个点的情况。
#include<bits/stdc++.h>
using namespace std;
int a[10005];//点
queue<int > tag;//记录符合l,r的点的集合。
struct se//区间
{
int x,y;
}d[10005];
bool cmp(se a,se b)
{
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<m;i++)
cin>>d[i].x>>d[i].y;
sort(d,d+m,cmp);
// for(int i=0;i<n;i++) cout<<a[i]<<' '; cout<<endl;
// for(int i=0;i<m;i++) cout<<d[i].x<<' '<<d[i].y<<' '<<"zzz"<<endl;
int z=1,j=0,sum=0,l,r;
d[m].x=1000000000,d[m].y=1000000000;
for(int i=0;i<=m;i++)
{
if(d[i].x>l) l=d[i].x;
if(d[i].y<r) r=d[i].y;
if(tag.size()&&(l>tag.front()||r<tag.front()))
{
while(tag.size()&&(l>tag.front()||r<tag.front()))
{
//cout<<tag.front()<<" ci"<< ' '<<d[i].x<<' '<<d[i].y<<endl;
tag.pop();
if(tag.size()==0)
{
sum++;
z=1;
break;
}
}
}
if(z)
{
l=d[i].x;
r=d[i].y;
for(j=0;j<n;j++)
if(a[j]>=d[i].x&&a[j]<=d[i].y)
tag.push(a[j]);
z=0;
// cout<<d[i].x<<' '<<d[i].y<< ' '<<"tag"<<endl;
//cout<<j<<' '<<" s"<<' '<<tag.front()<<' '<<tag.back()<<endl;
}
}
//cout<<sum<<endl;
// cout<<tag.size()<<endl;
if(!sum) cout<<"-1"<<endl;
else cout<<sum<<endl;
}
}