Description
假设海岸线是一条无限长的直线,陆地位于海岸线的一边,大海位于海岸线的另一边。大海中有许多小岛。某安全部门为了监视这些岛上是否有敌人入侵,打算在海岸线上安装若干个雷达来检测岛屿的情况。每个雷达的覆盖范围是以雷达中心为圆心,半径为(d)的圆形区域。
我们用平面之间坐标系来表示整个区域,海岸线为(x)轴,大海位于(x)轴上方,陆地位于(x)轴下方。为了节约成本,安全部门想使用最少的雷达覆盖所有的岛屿。现在已知每个岛屿的坐标((x,y))和雷达的覆盖半径(d),你的任务就是计算出能够覆盖所有岛屿的最少雷达数量。
Solution
这道题的贪心思路就是对于一个未被覆盖的海岛,肯定是贪心地把雷达放在能覆盖到它的最右边的地方。但是排序不是按(x)坐标排序,而是按r排序,因为(r)越小,把雷达放在(r)能覆盖到的岛屿(之前的)就会更多,如果(r)比较大,就可能会漏掉前面的一些岛屿,且我们是按(r)贪心,肯定也要按(r)排序。
然后这题要开(double),注意实数比较大小会有误差,要用(eps)。
Code
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6;
int n, t, bk[1005];
struct node
{
double x, y, r;
}p[1005];
double d;
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
int cmp(node a, node b)
{
return a.r < b.r || (a.r == b.r && a.y > b.y);
}
int main()
{
while (1)
{
n = read(); scanf("%lf", &d);
if ((!n) && (!d)) break;
double mx = 0;
for (int i = 1; i <= n; i ++ )
{
scanf("%lf %lf", &p[i].x, &p[i].y);
mx = max(mx, p[i].y);
p[i].r = p[i].x + sqrt(d * d - p[i].y * p[i].y);
}
sort(p + 1, p + n + 1, cmp);
t ++ ;
printf("Case %d: ", t);
if (mx > d)
{
puts("-1");
continue;
}
double pos;
int res = 0;
for (int i = 1; i <= n; i ++ )
{
pos = p[i].x + sqrt(d * d - p[i].y * p[i].y);
res ++ ;
for (int j = i + 1; j <= n; j ++ )
{
i = j;
if (p[j].y * p[j].y + (pos - p[j].x) * (pos - p[j].x) - d * d > eps)
{
i -- ;
break;
}
}
}
printf("%d
", res);
}
return 0;
}