http://poj.org/problem?id=1328
题意
x
x
x 轴上方是海,下方是陆地,海上有
n
n
n 个小岛。在陆地上建若干个探测半径为
d
d
d 的雷达,要保证所有小岛都可以覆盖到,求最少要修多少个雷达,输出最少雷达数量,无解则输出
−
1
-1
−1。
分析
无解的情况
显然,当 y i > d y_i\gt d yi>d 时无解。
雷达的位置
- 雷达必定修建在海岸线( x x x 轴)上
- 在1的前提下,可以计算,要使第
i
i
i 个海岛(设坐标为
(
x
i
,
y
i
)
(x_i, y_i)
(xi,yi))被覆盖到,雷达在
x
x
x 轴上对应的区间
[
l
i
,
r
i
]
[l_i,r_i ]
[li,ri]。其中,
l
i
=
x
i
−
d
2
−
y
i
2
l_i =x_i -\sqrt {d^2 - y_i^2}
li=xi−d2−yi2
r
i
=
x
i
+
d
2
−
y
i
2
r_i =x_i +\sqrt {d^2 - y_i^2}
ri=xi+d2−yi2
(
y
i
≤
d
)
(y_i\le d)
(yi≤d)
雷达的数量
每一个雷达都应该尽可能多覆盖一些小岛。将所有小岛对应的
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 按
l
i
l_i
li 从小到大排序,则每个雷达可以覆盖的小岛在排序后的序列中是连续的。
从左到右遍历
[
l
i
,
r
i
]
[l_i, r_i]
[li,ri],每次仅考虑一个雷达,用
[
L
,
R
]
[L, R]
[L,R] 表示当前雷达要覆盖若干个小岛,应该修建在
[
L
,
R
]
[L,R]
[L,R] 区间上。
对于
[
l
i
,
r
i
]
[l_i, r_i]
[li,ri],有三种情况(由于
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 是排过序的,不会有
l
i
<
L
l_i\lt L
li<L 的情况)
-
l i ≥ L , r i ≤ R l_i \ge L, r_i\le R li≥L,ri≤R
[ l i , r i ] [l_i, r_i] [li,ri] 完全被 [ L , R ] [L, R] [L,R] 覆盖,任何建在 [ L , R ] [L, R] [L,R] 区间上的雷达都可以覆盖 [ l i , r i ] [l_i,r_i] [li,ri]。 -
l i ≤ R , r i ≥ R l_i \le R, r_i \ge R li≤R,ri≥R
[ l i , r i ] [l_i, r_i] [li,ri] 和 [ L , R ] [L, R] [L,R] 有一部分重叠,显然,雷达应建在重叠的部分。 -
l i > R l_i \gt R li>R
[ l i , r i ] [l_i, r_i] [li,ri] 和 [ L , R ] [L, R] [L,R] 完全不重叠,必须新建一个雷达。
代码
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct segment
{
double l, r;
bool operator < (const segment & b) const
{
if(l == b.l) return r > b.r;
return l < b.l;
}
}sgm[1005];
int main()
{
int n, d;
int kase = 0;
while(scanf("%d%d", &n, &d) == 2)
{
if(!n && !d) break;
int ans = 1;
for(int i = 0; i < n; i ++)
{
int x, y;
scanf("%d%d", &x, &y);
if(y > d)
ans = -1;
double tmp = sqrt(double(d * d - y * y));
sgm[i].l = x - tmp;
sgm[i].r = x + tmp;
}
if(ans < 0)
{
printf("Case %d: -1\n", ++kase);
continue;
}
sort(sgm, sgm + n);
double lft = sgm[0].l, rt = sgm[0].r;
for(int i = 1; i < n; i ++)
{
if(sgm[i].l >= lft && sgm[i].r <= rt)
{
lft = sgm[i].l;
rt = sgm[i].r;
}
else if(sgm[i].l <= rt && sgm[i].r >= rt)
lft = sgm[i].l;
else if(sgm[i].l > rt)
{
lft = sgm[i].l;
rt = sgm[i].r;
ans ++;
}
}
printf("Case %d: %d\n", ++kase, ans);
}
return 0;
}