题目概述
一个无线路由,其覆盖范围只有前方半径为R的半圆区域,路由器放在点T且不可移动,但可调整信号的方向,附近有N个人站在原地,给定其坐标,问无线信号最多可覆盖多少人
在范围边界的人也会被覆盖到,不会有人站在路由器上
时限
1000ms/3000ms
输入
第一行两个整数和一个正浮点数,描述路由器坐标及其覆盖半径R,下一行正整数N,其后N行,每行两个整数,描述一个人的坐标,输入到R<0结束
限制
0<=所有整数<=1000;R>0;1<=N<=150
输出
每行一个数,为所求最大覆盖数
样例输入
25 25 3.5
7
25 28
23 27
27 27
24 23
26 23
24 29
26 29
350 200 2.0
5
350 202
350 199
350 198
348 200
352 200
995 995 10.0
4
1000 1000
999 998
990 992
1000 999
100 100 -2.5
样例输出
3
4
4
讨论
计算几何,这个应该放到一开始基础题部分做,枚举人和路由器的连线,计数在半径范围内且在连线右侧的人,最后返回最大值即可,平方级复杂度,但是数据规模小,因而还是很快的
另一种方法是先排除掉所有在半径外的点,剩下的点按相对于路由器的极角排序,之后每次枚举连线,然后二分找到第一个在连线左侧的人,便可求得范围中的人数,线性对数级复杂度,不过代码会更长一些,为防不必要的麻烦,没有尝试
题解状态
192K,0MS,C++,1090B
题解代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1003
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-8
struct Pt//point 点的结构
{
int x, y;
}T, pts[MAXN];//transmitter 发射器(路由器)的点 points 人的点
int N;//人总数
double R;//覆盖半径
int xp(Pt &a, Pt &b, Pt &c)//向量积
{
return (a.x - b.x)*(c.y - b.y) - (a.y - b.y)*(c.x - b.x);
}
double dis(Pt &a, Pt &b)//两点间距离
{
return sqrt(double(a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));//整型重载sqrt是c++11才有的 因而利用强转使其重载double型sqrt
}
int signal(double a)//符号函数
{
return abs(a) < EPS ? 0 : (a > 0 ? 1 : -1);
}
int fun()
{
for (int p = 0; p < N; p++)
scanf("%d%d", &pts[p].x, &pts[p].y);//input
int most = 0;//最大覆盖人数
for (int p = 0; p < N; p++) {//枚举一个人 和路由器连线做半径
int cnt = 0;
for (int i = 0; i < N; i++)//枚举其他人 进行判断
if (signal(dis(pts[i], T) - R) <= 0 && xp(pts[i], T, pts[p]) >= 0)//在半径内 且在连线右侧
cnt++;
most = max(most, cnt);
}
return most;
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
while (~scanf("%d%d%lf", &T.x, &T.y, &R) && signal(R) > 0) {//input
scanf("%d", &N);//input
printf("%d\n", fun());//output
}
}
EOF