[ 題目描述] 假設有一條無限長的海岸線,在海的那一半有n個島嶼。在海岸線上有雷達,每個雷達能夠探測的範圍為半徑為d的圓,一個島嶼能被雷達探測到,若且唯若它與雷達的距離小於等於d。
我們用直角座標系來抽象這些,x軸為海岸線,x軸上面為海,x軸下面為陸地()。
{
img_auto_size(this,450,true);
}" align="absMiddle" vspace="1">
給出所有島嶼的座標和雷達的半徑。求最少需要用多少個雷達,使得所有的島嶼都被探測到。(無解輸出-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;
}