1328Radar Installation:如何贪心+坑点记录+一组样例数据

题目大意

假设海岸是无限的直线。 陆地在海岸的一侧,海洋在另一侧。 每个小岛都是位于海边的一个地点。 而且,位于海岸上的任何雷达装置只能覆盖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;
	}
}

完成了这道题,建议做一下这道题,这两道题的内在思想是一致的,不过是算法的叠加。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值