POJ1328踩坑指南

题干

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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值