题干
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.
Figure A Sample Input of Radar Installations
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
题干解读
假设海岸线是一条无限延伸的直线,陆地在海岸线下侧,海洋在上侧,岛屿是海洋上的一个点(x轴上方),雷达布置于海岸线(y=0),求需要多少个雷达能够覆盖全部岛屿,若不可覆盖输出-1。
思路
失败条件
如果存在某个island的y值比范围d还大的话,一定是无法覆盖到的,没得说肯定是失败了。
解法思路
很明显的一道贪心,那么我们先把岛屿们按照x轴排个序,然后从左侧第一个岛屿开始,贪心的把雷达尽可能的向x轴右侧放置(称为该岛屿点位的理想雷达地点),囊括后面尽可能多的点,然后对后面的点进行判断是否在上一个雷达的覆盖范围内。
如果不在范围内则存在两种情况,需要分类处理:
- 情况一:点位太靠右无法放入前一个雷达范围(则此点位算出来的理想雷达放置地点在前一个雷达点的右侧)。此时雷达总数+1,最右雷达位置更新。
- 情况二:点位不是很靠右(在最后一个雷达点位的左侧),但是太高了,导致无法进入雷达范围(此点位算出来的雷达理想地点在前一个雷达点左侧)。此时将该雷达点回拉,仅更新雷达位置,不增加雷达总数。
P.S:思考一下,绝对不会出现这种情况:某岛屿点位在最后一个雷达的左侧,无法进入该雷达范围且理想雷达点位在原有雷达点位的右侧。
坑们
- 首先,岛屿必须在海面上,所以岛屿的y值必须大于0,否则直接失败,等于0好像也不行,没有进行过尝试。
- 由上一条知道,距离d很可能也不能等于0。
- 非常重要:输出不只有ans,还得把Case啥的加上。。。因为这个问题被坑了好几个wa(我是伞兵呜呜呜呜
- 雷达的位置不可以用整数表示,用double进行计算,注意不要中间带成整数导致丢失精度。
解法代码
#include <iostream>
#include <math.h>
#include <algorithm>
#include <cmath>
using namespace std;
struct island{
int x;
int y;
bool operator<(const island &is)const{
if( x == is.x )
return( y * y > is.y * is.y );
return (x < is.x);
}
};
int area;
island lands[1005];
int ans;
double lastpointo,lastpointn;
bool isIn(double x , island is){
return ((is.x-x) * (is.x-x) + (is.y*is.y) <= area*area);
}
//false表示无法覆盖,只要能覆盖到无论是否添加雷达返回的都是true。返回false直接输出-1就行了。
bool isAdd(island is){
if (is.y > area || is.y < 0) return false;
if (isIn(lastpointo , is)) return true;
lastpointn = (double)is.x + sqrt((double)(area*area - is.y*is.y));
if(lastpointn < lastpointo) {
lastpointo = lastpointn;
}else{
ans++;
lastpointo = lastpointn;
}
//cout<<"ln="<<lastpointo<<" "<<is.x<<" "<<is.y<<" "<<endl;
return true;
}
int main(){
int num = 1;
for( ; ;num++){
int n;
scanf("%d%d",&n,&area);
if(n == area && n == 0){
return 0;
}
ans = 0;
for(int i = 0 ; i < n ; i++){
scanf("%d%d",&lands[i].x,&lands[i].y);
}
sort(lands , lands+n);
if( lands[0].y < 0 || lands[0].y > area || area < 0){
cout<<"Case "<<num<<": -1"<<endl;
continue;
}else{
lastpointo = (double)lands[0].x + sqrt((double)(area*area - lands[0].y*lands[0].y));
ans++;
}
//cout<<"ln="<<lastpointo<<endl;
bool flag = 0;
for(int i = 1 ; i < n ; i++){
if(!isAdd(lands[i])){
cout<<"Case "<<num<<": -1"<<endl;
flag = 1;
break;
}
}
if(!flag){
cout<<"Case "<<num<<": "<<ans<<endl;
}
}
return 0;
}