[ 题目描述] 假设有一条无限长的海岸线,在海的那一半有n个岛屿。在海岸线上有雷达,每个雷达能够探测的范围为半径为d的圆,一个岛屿能被雷达探测到,当且仅当它与雷达的距离小于等于d。
我们用直角坐标系来抽象这些,x轴为海岸线,x轴上面为海,x轴下面为陆地(如图)。
给出所有岛屿的坐标和雷达的半径。求最少需要用多少个雷达,使得所有的岛屿都被探测到。(无解输出-1)
【分析】这道题目很容易想到用贪心的方法,找一个圆,并且这个圆覆盖得点越多越好。
我们可以将所有的点用一种方法映射到x轴上,成为圆心。最容易想到的是垂直投影,这样x轴上的每一个点为圆心的圆一定可以覆盖正上方的岛屿,就可以使用贪心法了。但是这样做是错的,因为如果点的纵坐标小于d,则会造成圆的浪费,为了极大限度的利用圆(贪心思想),应该寻找每个点对应的圆心(点在圆上,圆心在点右侧)。再从左到右遍历一遍,就可以完美的解决问题。(引用http://liymouse.bokee.com/5017529.html)
//利用贪心思想解决
#include <iostream>
#include <cmath>
//--------------------------------
using namespace std;
typedef struct p
{
int x;
int y;
}point;
typedef struct b
{
float left;
float right;
}bound;
int compare(const void *p1,const void *p2)
{//used by qiuck sort
bound a=*(bound *)p1;
bound b=*(bound *)p2;
if(a.left>b.left)
return 1;
else if(a.left==b.left && a.right>b.right)
return 1;
return -1;
}
int main()
{
int i;
int num=0;
int n,d;
point p[1000];
bound b[1000];
while(1)
{
int flag=0;
num++;
int count=1;
cin >> n >> d;
if(n==0 && d==0)
exit(1);
for(i=0;i<n;i++)
{
cin >> p[i].x >> p[i].y;
float temp=sqrt((float) (d*d-p[i].y*p[i].y) );
b[i].left=p[i].x-temp;
b[i].right=p[i].x+temp;
if(p[i].y>d)
flag=1;
}
if(d<=0 || flag==1)
{
cout << "Case " << num << ": " << -1 << endl;
continue;
}
qsort(b,n,sizeof(bound),compare);
float right=b[0].right;
for(i=1;i<n;i++)
{
if(b[i].left>right)
{
count++;
right=b[i].right;
}
else if(b[i].right<right)
right=b[i].right;
}
cout << "Case " << num << ": " << count << endl;
}
return 0;
}