poj 1328 Radar Installation
/*
一般我们的做法都是正向思维,即先对横坐标排好序,再枚举横坐标的整点,
然后贪心做,其实这样做是很费力的。
可以逆向思维考虑一下:
最多只有1000的点,我们可以先预处理完以该点为圆心,半径为d的圆与横坐标的左右交点
(当然还可能只有1个,或者没有),然后分别储存到结构体的两个关键字中,然后尽量再枚举
后面的点的区间与前面的点的区间(两个关键字构成的区间)有交集(贪心,因为事先排好序),
再向后面延展的同时,使得雷达的数量最小化,直到遇到没有交集的点为止
(我的文字可能不清晰,具体看代码)
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define X 1005
int n,d;
struct node
{
double x,y;
friend bool operator <(node a,node b)//重载符号,方便排序
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
}p[X];
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int cnt = 0;
while(cin>>n>>d,n||d)
{
int ans = 0,x,y;
double temp;
int t;
bool flag = true;
if(d<0) //若覆盖距离小于0,直接fold掉
flag = false;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
if(flag) //若之前已经不成立了,无需再插入到结构体中,剪枝
{
t = d*d-y*y;
if(t<0||y<0)
{
flag = false;
continue;
}
temp = sqrt(t*1.0); //注意若t<0时会出错的
p[i].x = x-temp; //以改点为圆心以d为半径的圆与x轴的两个交点(可能为一个)
p[i].y = x+temp;
}
}
if(!flag)
printf("Case %d: %d\n",++cnt,-1);
else
{
sort(p,p+n);
temp = p[0].y; //它所能覆盖的最大x的坐标
for(int i=1;i<n;i++)
{
if(p[i].x>temp)//如果后面的点的左边的值已经比它大,说明需要添加雷达,同时更新temp
{
ans++;
temp = p[i].y;
}
else if(p[i].y<temp)//若后面的点的最大能覆盖到的距离比之前的还小,更新一下
temp = p[i].y;
}
printf("Case %d: %d\n",++cnt,ans+1);
}
}
return 0;
}