区间选点详情可以参照刘汝佳的紫书中的描述。这里大概叙述一下这类题目的做法。
区间选点:给出n个区间,问至少用多少个点使得每个区间至少有一个点。
做法:1、对n个区间按右端点从小到大排序,如果右端点相等则按左端点排序。
2、然后从排序后的第一个区间出发,设置当前覆盖区间右侧为该区间的右边。
3、只有当下一个区间的左端点大于当前被覆盖的右端点时,点数才加1.(注意刚开始放了一个点)
poj1328:给一个横坐标,然后坐标上方有n个点,问至少画圆心在坐标轴上的圆多少个可以覆盖所有的n个点。
这题除了上述步骤外还需把能覆盖某一点的圆心坐标范围转化成区间,接着就是区间选点问题了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e3+50;
int n,casenum=0,cnt;
double d,x,y,posr;
bool flg;
struct seg{
double l,r;
}s[maxn];
bool cmp(seg a,seg b){
if(a.r==b.r)
return a.l>b.l;
return a.r<b.r;
}///按右端点从小到大排序,如果相同则按左从大到小
int main(){
//freopen("out.txt","w",stdout);
while(scanf("%d%lf",&n,&d)!=EOF){
if(!n&&!d) break;
flg=false;
for(int i=0;i<n;i++){
scanf("%lf%lf",&x,&y);
double dist=sqrt(d*d-y*y);
s[i].l=x-dist;
s[i].r=x+dist;
if(y>d) flg=true;
}
if(flg){
printf("Case %d: -1\n",++casenum);
continue;
}
sort(s,s+n,cmp);
posr=s[0].r;///当前覆盖区间右端
cnt=1;
for(int i=1;i<n;i++)
if(s[i].l>posr){///下一个区间的左端点大于当前被覆盖的右端点
cnt++;
posr=s[i].r;
}
printf("Case %d: %d\n",++casenum,cnt);
}
return 0;
}
poj 3485
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <cmath>
#include <algorithm>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+50;
int l,d,n,cnt;
double x,y,posr;;
bool flg;
struct seg{
double l,r;
}s[maxn];
bool cmp(seg a,seg b){
if(a.r==b.r)
return a.l>b.l;
return a.r<b.r;
}
int main(){
while(scanf("%d%d%d",&l,&d,&n)!=EOF){
flg=true;
for(int i=0;i<n;i++){
scanf("%lf%lf",&x,&y);
double dist=sqrt(d*d*1.0-y*y*1.0);
s[i].l=x-dist;
s[i].r=x+dist;
if(y>d) flg=false;
}
if(!flg){
printf("0\n");
continue;
}
sort(s,s+n,cmp);
cnt=1;
posr=s[0].r;
for(int i=1;i<n;i++){
if(posr>l)
posr=l;
if(s[i].l>posr){
cnt++;
posr=s[i].r;
}
}
printf("%d\n",cnt);
}
return 0;
}