《算法竞赛进阶指南》0x07贪心 POJ1328

题目链接:http://poj.org/problem?id=1328

给出平面上N个点,要求在横轴上放置最少的点来覆盖N个点,其中每个点的覆盖半径都是R,可以将问题转化成用点覆盖线段的问题,计算N个点中每个点的可被管辖区间,

转化成求每个线段中至少有一个点的最少的点数。贪心思想。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100010
const double eps=1e-6;
struct node{
    int x,y;
    double l,r;//l,r为能够管辖这个点的区间 
    bool operator < (const node& a)const {
        return l<a.l;//按照左端点进行升序排序 
    }
}a[maxn];
int n,d;
int main (){
    int kase=0;
    while(cin>>n>>d){
        if(n==0 && d==0)break;
        for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
        bool flag=true;
        for(int i=1;i<=n;i++){
            if(a[i].y>d){
                flag=false;
                break;
            }
            double k=sqrt((double)d*d-(double)a[i].y*a[i].y);
            a[i].l=a[i].x-k,a[i].r=a[i].x+k;
        } 
        if(!flag){
            cout<<"Case "<<++kase<<": "<<-1<<endl;
            continue;
        }
        sort(a+1,a+n+1);
        int ans=0;
        double pos=-1e10;
        for(int i=1;i<=n;i++){
            if(pos+eps<a[i].l){//浮点数无法严格比较 
                ans++;//重新开一个段 
                pos=a[i].r;
            }else{
                pos=min(pos,a[i].r);//在满足第i个区间的情况下,使点尽量靠后,之前能覆盖的点不受影响 
            }  
        }
        printf("Case %d: %d
",++kase,ans);
    }
}
原文地址:https://www.cnblogs.com/randy-lo/p/13139363.html