POJ:1328 Radar Installation 解题思路(采用优先队列和栈实现)、注意点以及部分测试数据

POJ:1328 Radar Installation 解题思路(采用优先队列和栈实现)、注意点以及部分测试数据

本题选自PKU Online Judge(POJ)——http://poj.org/ 当中的第1328

题目不难,但是比较经典,主要的思路是采用贪心算法求解,但是需要转化一下才行,网络上也有其他的博主写关于此题的思路,但是我这里主要是采用STL方式进行解题(priority_queue&stack),这使得我的方法写出的代码不会涉及太多循环变量,也没有建立新的数据结构,代码量仅控制在50行以内,先看题。

Radar Installation

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 123563 Accepted: 27315

Description

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d. 

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates. 

Input

The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases. 

The input is terminated by a line containing pair of zeros 

Output

For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. "-1" installation means no solution for that case.

Sample Input

3 2
1 2
-3 1
2 1

1 2
0 2

0 0

Sample Output

Case 1: 2
Case 2: 1

Source

Beijing 2002

我先用中文大概讲一下题目意思:

给定一个直角坐标系,定义x轴为海岸线,海岸线上方是海,下方是陆地。在海域零星分布一些海岛, 需要要在海岸线上安装若干个雷达覆盖这些海岛,每个雷达的覆盖半径都是相同且固定的。现在给定所有海岛的坐标(x,y), 以及雷达的覆盖半径d,问可以覆盖所有海岛的最小雷达数。

解题思路:

    首先可以明确的是:只要存在任意一个海岛位置超出雷达最大覆盖半径(即y>d),则无解.
    在所有海岛的 y<=d 的前提下去思考此问题,那么此问题的切入点是需要知道【一个雷达要覆盖一个海岛,其可以安装范围是多少】
    以海岛坐标(x,y)为圆心,用雷达覆盖半径d画圆,根据前提条件可知,这个圆与x轴必定存在最少1个(y=d)、最多2个交点(y<d).
    可以认为1个交点是2个交点重合的特殊情况,那么这2个交点在x轴上构成的线性区间,可以看作海岛的被覆盖范围在x轴上的投影 (由此就可以把二维的几何问题转化成一维几何问题)
    按照所有海岛的x轴坐标,从小到大依次计算每个海岛在x轴上的投影区间(投影可能存在重叠),同时把每个雷达抽象成1个点,那么此问题就转化成:【已知x轴上若干个区间(可能存在交集),现在要往这些区间内放若干个点,问怎样放置这些点,使得每个区间内至少存在一个点,且所放置的点的总量尽可能最少】
 
    可使用贪心算法求解:

    根据每个区间的左端点坐标对所有区间从左到右排序:

  1.  在左起第一个区间A的右端点A.R放置一个点,总放置点数P+1 。
  2.  若下一个区间B的左端点B.L > A.R, 说明区间A与区间B无交集,此时在区间B的右端点B.R放置一个点,总放置点数P+1,否则说明 区间A与区间B相交, 此时进一步判断,若B.R <= A.R,说明区间B在区间A的内部,此时把原本放置在 A.R 的点移动到 B.R(确保区间B有一个点),总放置点数不变。
  3.  重复这个过程直到所有区间被遍历完成。

下面给出AC代码:

#include <iostream>
#include <queue>
#include <math.h>
#include <stack>
#include <stdio.h>

using namespace std;

int main(void){
	int n, R, index = 0;
	while (scanf("%d%d", &n, &R) != EOF){   // 注意,如果你是用cin输入出现"Time Limit Exceeded"的情况,在保证你的代码没有出现因为复杂度上的问题时请用scanf进行输入 
		index++;
		if (n == 0 && R == 0) break;
		int num = -2;
		priority_queue<pair<float, float> > pqu;   // 优先队列,里面按照pair的第一个元素进行由大到小的排列,second递归次之 
		stack<pair<float, float> > qu;   //  将优先队列里面的元素反过来,使由小到大排列 
		for (int i = 0; i < n; i++){
			float x, y;
			scanf("%f%f", &x, &y);
			if (y > R || y < 0){   //  注意别漏掉y < 0的情况,也就是海岛不能在陆地上 
				num = -1;
				continue;
			}
			float sta = sqrt(R * R * 1.0 - y * y) + x, end = x - sqrt(R * R * 1.0 - y * y);
			pair<float, float> pa(sta, end);
			pqu.push(pa);
		}
		if (num == -1){
			cout<<"Case "<<index<<": "<<num<<endl;
			continue;
		}
		num = 0;
		while (pqu.empty() != true){   //  倒置优先队列里面的元素到栈当中 
			pair<float, float> pa = pqu.top();
			pqu.pop(), qu.push(pa);
		}
		while (qu.empty() != true){
			pair<float, float> pa = qu.top();
			qu.pop(), num++;
			while(qu.empty() != true){
				pair<float, float> temp = qu.top();
				if (temp.second <= pa.first) qu.pop();   //  注意 temp.second <= pa.first当中的<=符号,海岛在雷达所在范围圆上也是成立的 
				else break;
			}
		}
		cout<<"Case "<<index<<": "<<num<<endl;
	}
	return 0;
}

在这里需要注意的几点列出如下:

  • 在程序当中,如果你是用cin输入,提交后出现"Time Limit Exceeded"的情况,在保证你的代码没有出现因为复杂度上的问题时,请用scanf进行输入 (程序11和19行)
  • 输入过程当中注意别漏掉y < 0的情况,也就是海岛位置不能在陆地上(程序20行)
  • 海岛是允许刚好在雷达探测的圆上(程序42行)

另外如果你的代码仍然Wrong Answer,先试一试我底下列举出的部分测试数据,一个个测试观察是否正确:

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

2 5
0 3
8 3

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
Case 21: 1

本人写出的代码当中还涉及到STL的相关知识,主要是优先队列的运用,不懂可以去查一查文档看看。

如果这题搞懂了可以尝试做一做这一道题POJ 3069——Saruman's Army,思路和上面基本类似。

也欢迎大家访问我的主页,我会分享一些自己学习过程当中的技术和想法,谢谢支持。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值