您的位置:首页 > 其它

poj 1328 && uva 1193 && la 2519

2016-08-31 15:28 246 查看

题目概述

在直角坐标系中,x轴为海岸线,其上方为海,海上有N个小岛位于x,y,现要在海岸线建雷达站,所有雷达覆盖范围都是R,问所有岛可否被雷达覆盖,若可,求最少雷达数

海岛不会在陆地上

时限

1000ms/3000ms

输入

第一行两个整数N,R,其后N行,每行两个整数x,y,输入到N=R=0为止

4000

限制

1<=N<=1000

输出

每行一个字符串

Case A: B

其中A为数据序数,从1开始,若有岛无法被雷达覆盖,B=-1,否则B为所求雷达数

样例输入

3 2

1 2

-3 1

2 1

1 2

0 2

2 2

1 1

2 2

0 0

样例输出

Case 1: 2

Case 2: 1

Case 3: 1

讨论

贪心,首先排序是必不可少的,但一开始很容易当成poj 3069那样每次都把圆尽可能右移,但是如样例3,这样会导致移过了而多算圆,因而需要一点改进,遇到一个点,先按照上面的方法求出圆心,之后对于所有在圆心左侧的点,如果点在圆外,则将圆心左移,当然,这里已经排除了无解的情况

题解状态

192K,16MS,C++,1047B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1004
#define memset0(a) memset(a,0,sizeof(a))

struct Pt//点的结构
{
int x, y;
bool operator<(const Pt &b)const
{
return x != b.x ? x < b.x : y < b.y;
}
}pts[MAXN];
int N, R;//点总数 圆半径
int fun()
{
bool f = 0;//是否存在完全不可能被圆覆盖到的点
for (int p = 0; p < N; p++) {
scanf("%d%d", &pts[p].x, &pts[p].y);//input
if (pts[p].y > R)//即到海岸线距离大于圆半径
f = 1;
}
if (f)
return -1;
sort(pts, pts + N);
int cnt = 0;//最少圆个数
for (int p = 0; p < N; p++, cnt++) {//枚举一个未被覆盖的点
double x = sqrt(double(R*R) - (pts[p].y*pts[p].y));//求出圆心横坐标与这个点横坐标差值
int i = p + 1;
for (; i < N&&pts[i].x <= x + pts[p].x; i++)//枚举在圆心左侧的点
x = min(x, sqrt(double(R*R) - (pts[i].y*pts[i].y)) + pts[i].x - pts[p].x);//调整圆心位置使得这些点都能被圆覆盖
x += pts[p].x;//现在表示圆心横坐标了
for (; i < N && (pts[i].x - x)*(pts[i].x - x) + pts[i].y*pts[i].y <= R*R; i++);//数出最多可以覆盖多少在圆心右侧的点
p = i - 1;//重新选取一个未被覆盖的点 由于p++的存在 因而要-1
}
return cnt;
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);

int times = 0;
while (~scanf("%d%d", &N, &R) && (N || R))//input
printf("Case %d: %d\n", ++times, fun());//output
}


EOF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: