问题 1555: 线段和点 (思维)
问题 1555: 线段和点
题意:
给你n个点,m个区间,求出最少的点集使得覆盖所有的区间
思路:
我们先对区间排下序,然后我们向后遍历的时候,用两个指针
只记录到当前重叠的区间,则在这些区间我们只选择重叠区间的一个点
即可,这样即使最少
然后我们具体是选择哪个点呢,这个可以先将满足的点先全部用队列存起来,
然后我们在求重叠区间的过程中,可以边去掉一些不要的点。
如果队列为空的时候,证明这是出现了新的区间,之前的重叠区间不能将其
包括进来,这时候就要再加一个新的点了。
代码:
#include<bits/stdc++.h> using namespace std; #define N 10004 int n,m; int a[N]; struct node { int L; int R; bool operator <(const node &p) const{ if(L!=p.L) return L<p.L; else return R<p.R; } }s[N]; queue<int>q; int main() { while(~scanf("%d %d",&n,&m)) { for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) { scanf("%d %d",&s[i].L,&s[i].R); } sort(s,s+m); while(q.size()) q.pop(); int sum=0,L=s[0].L,R=s[0].R; bool flag=1; bool f=1; for(int i=0;i<m;i++) { if(s[i].L>L)L=s[i].L; if(s[i].R<R) R=s[i].R; if(q.size()&&(L>q.front()||R<q.front())) { while(q.size()&&(L>q.front()||R<q.front())) { q.pop(); if(q.size()==0) { sum++; flag=1; } } } if(flag) { L=s[i].L; R=s[i].R; flag=0; bool v=0; for(int j=0;j<n;j++) { if(a[j]>=s[i].L&&a[j]<=s[i].R) { q.push(a[j]); v=1; } } if(!v) { f=0; break; } } } if(f) printf("%d\n",sum+1); else printf("-1\n"); } return 0; }