B - 区间选点(编译器选GNU G++)POJ1328
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
Input
第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)
Output
一个整数,代表选点的数目
Examples
Input
2
1 5
4 6
Output
1
Input
3
1 3
2 5
4 6
Output
2
思路与收获
这种区间的题目最好是在纸上画一画,可以极大帮助思路的形成。
这道题可以这么理解:把这些区间比作图的节点,区间重合就是节点连同,该题所求的点数就是图的连同分量数目了。
什么情况下需要新开一个连同分量?唯一的情况就是上一个区间的终点小于下一个区间的起点,这种情况下两个区间互不重合,必须有两个点分别被两个区间覆盖。
其他的区间间相互关系要么属于上述关系,要么不属于上述关系,所有不属于上述关系的情况都不需要新开连同分量。我们可以手动画一下,就知道这样做是正确的(所以动手画太重要了)。
基本思路就是:只关注互不重合的区间,忽略那些和当前区间重合的区间。 两区间是否重合的办法就是: 上一个区间的终点小于当前区间的起点,则两个区间互不重合。 为了简化上述标准的判断,可以将所有区间按照结束位置排序。
具体流程可以看代码,代码比口述流程严禁多了。
tips:画区间并不生动,有可能看走要配错括号,画线段就好多了。
#include<algorithm>
#include<cstdio>
using namespace std;
struct node {
int a,b;
bool operator < (node& y) {
return
(b<y.b)
||
(b==y.b&&a<y.a);
}
};
int main() {
//freopen("inb.txt","r",stdin);
int n;
scanf("%d",&n);
node c[n];
for(int i=0; i<n; i++)scanf("%d %d",&c[i].a,&c[i].b);
//将区间排序,便于我们遍历
sort(c,c+n);
int flag=c[0].b;
int count=1;
//遍历所有区间
for(auto item:c) {
//只需关注那些互不重合的区间,忽略那些和当前区间重合的区间
//手动画图跑一下代码会比较好理解,画线段比画区间更形象
//遇到右端点更右的区间的左端点,证明这个遇到了一个新的不重合的区间,因此点数加一
if(flag<item.a) {
flag=item.b;
count++;
}
}
printf("%d",count);
}