题目大意
假设海岸是无限的直线。 陆地在海岸的一侧,海洋在另一侧。 每个小岛都是位于海边的一个地点。 而且,位于海岸上的任何雷达装置只能覆盖d距离,因此,如果它们之间的距离最大为d,则可以用半径装置覆盖海中的一个岛。
我们使用笛卡尔坐标系,定义了惯性运动为x轴。 海洋一侧在x轴上方,陆地一侧在x轴上方。 给定海洋中每个岛的位置,并确定雷达装置覆盖的距离,您的任务是编写一个程序,以找到覆盖所有岛的最少雷达装置数量。 注意,岛的位置由其x-y坐标表示。
输入
输入包含几个测试用例。 每种情况的第一行包含两个整数n(1 <= n <= 1000)和d,其中n是海洋中的岛屿数量,d是雷达设备的覆盖距离。 随后是n行,每行包含两个表示每个岛位置坐标的整数。 然后出现空白行以分隔个案。
输入由包含零对的行终止
思路分析
显然是一个贪心的问题,对于一个岛k,能覆盖他的雷达必然有一个范围的限制:
对于x轴上方海岛,可以计算其x轴上被管辖的范围,大概就是以其自身为圆心,d为半径做圆,与x轴的左右交点便是L[i],R[i]。
然后问题就转化为:
给出n个区间,在x轴上放置最少的点,使得每个区间至少含有一个点。
然后就是一个经典的贪心,先按区间左端点从小到大排序,用pos记录已经安放的最后设备的坐标,初始pos为负无穷。
然后遍历每个区间,如果当前区间i的左端点大于pos(pos不能覆盖i),累加答案,令pos = R[i]
(放到能覆盖i的极限位置),否则令pos = min(R[i],pos)
(这个条件处理区间包含的情况)
比如蓝线部分,我们注意pos的位置,在判断了红点之后,我们把pos放在了红点最右端,然后判断黑点,此时我们最优的策略显然是把pos放在黑点的最右侧,所以才有了pos = min(R[i],pos)
。
2 5
-3 4
-6 3
4 5
-5 3
-3 5
2 3
3 3
20 8
-20 7
-18 6
-5 8
-21 8
-15 7
-17 5
-1 5
-2 3
-9 6
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 7
9 6
10 5
0 0
2 3
0 2
2 3
2 3
0 2
1 3
3 3
1 2
-3 2
2 4
8 5
2 4
-4 4
-3 3
-3 1
-3 0
-1 0
0 5
6 0
3 0
1 2
-3 1
2 1
3 2
1 2
-3 1
2 1
1 2
0 2
2 3
0 2
2 3
4 -5
4 3
4 3
2 3
6 -9
3 -3
1 2
-3 2
2 1
6 2
1 2
1 2
1 2
-3 1
2 1
0 0
1 2
0 2
2 3
0 2
1 3
3 10
1 10
2 3
4 5
3 5
1 10
2 3
4 5
4 7
1 10
2 3
4 5
0 0
3 9
1 10
2 3
4 5
0 0
================结果
Case 1: 1
Case 2: 2
Case 3: 4
Case 4: 1
Case 5: 1
Case 6: -1
Case 7: 3
Case 8: -1
Case 9: 2
Case 10: 1
Case 11: 1
Case 12: -1
Case 13: -1
Case 14: 2
Case 15: 1
Case 16: 1
Case 17: 1
Case 18: -1
Case 19: -1
Case 20: -1
挥着翅膀的鳖 献上。。。
d<=0不需要判断
y<=0 不需要判断
#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
#define MAX 1005
#define inf 0x7fffffff
int n, d, k = 1;
struct land {
double l, r;
land(double a = 0, double b = 0) { l = a, r = b; }
bool operator<(land ll) {
if (ll.l == l)return r < ll.r;
else return l < ll.l;
}
void set(double x, double y) {
double dis = sqrt(d*d - y * y);
l = x - dis, r = x + dis;
}
}arr[MAX];
int main() {
while (cin >> n >> d && n + d > 0) {
int sign = 1;
for (int i = 0; i < n; i++) {
int x, y; cin >> x >> y;
arr[i].set(x, y);
if (y > d)sign = 0;
}
printf("Case %d: ", k++);
if (!sign || d < 0) {
cout << -1 << endl; continue;
}
sort(arr, arr + n);
int cnt = 0;double pos = -inf;
for (int i = 0; i < n; i++) {
if (pos < arr[i].l) {//pos无法满足当前海岛的左端点约束
cnt++;
pos = arr[i].r;
}
else pos = min(pos, arr[i].r);
}
cout << cnt << endl;
}
}
完成了这道题,建议做一下这道题,这两道题的内在思想是一致的,不过是算法的叠加。