poj 1106

题目概述

一个无线路由,其覆盖范围只有前方半径为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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值