hiho 1508 剑刃风暴

极角排序,扫描线。
以每个点为圆心,画半径为r的圆,求最多覆盖的区间。
注意三角函数atan2很慢,尽量不要使用

#include <bits/stdc++.h>

using namespace std;

#define LL long long
#define pii pair<int, int>
#define MP make_pair
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-12
#define Pi acos(-1.0)
#define N 10050
#define M 200020
#define PB push_back
#define MP make_pair
#define fi first
#define se second

int dcmp(double x){
    if(fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}
struct point{
    double x, y;
    point(double x = 0, double y = 0) : x(x), y(y) {}
    point operator - (const point &b) const {
        return point(x - b.x, y - b.y);
    }
    point operator + (const point &b) const {
        return point(x + b.x, y + b.y);
    }
    point operator * (const double &k) const {
        return point(x * k, y * k);
    }
    point operator / (const double &k) const {
        return point(x / k, y / k);
    }
    bool operator == (const point &b) const {
        return dcmp(x - b.x) == 0 && dcmp(y - b.y) == 0;
    }
    double ang(){
        return atan2(y, x);
    }
    double len(){
        return sqrt(x * x + y * y);
    }
};
struct node{
    int in;
    double ang;
    node(double ang = 0, int in = 0) : ang(ang), in(in) {}
    bool operator < (const node &b) const {
        return dcmp(ang - b.ang) < 0 || (dcmp(ang - b.ang) == 0 && in > b.in);
    }
};
int circle_cross(point a, double ra, point b, double rb, double &ang1, double &ang2){
    double d = (a - b).len();
    if(dcmp(d - ra - rb) > 0) return 0;  //xiangli
    if(dcmp(fabs(ra - rb) - d) >= 0){
        if(dcmp(ra - rb) >= 0) return 0;
        else return -1;
    }
    double da = (ra * ra + d * d - rb * rb) / (2 * ra * d);
    double aa = atan2((b - a).y, (b - a).x);
    double rad = acos(da);
    ang1 = aa - rad, ang2 = aa + rad;
    return 1;
}
bool point_in_circle(point p, point o, double r){
    double d = (p - o).len();
    return dcmp(d - r) <= 0;
}

point p[N];
int n, cnt;
double r;
node t[N];

int main(){
    scanf("%d%lf", &n, &r);
    for(int i = 1; i <= n; ++i){
        scanf("%lf%lf", &p[i].x, &p[i].y);
    }
    int ans = 1;
    for(int i = 1; i <= n; ++i){
        cnt = 0;
        int tot = 1;
        for(int j = 1; j <= n; ++j){
            if(i == j) continue;
            if(p[i] == p[j]){
                ++tot; continue;
            }
            double ang1, ang2;
            int ok = circle_cross(p[i], r, p[j], r, ang1, ang2);
            if(ok == 1){
                if(ang1 > ang2) swap(ang1, ang2);
                double md = (ang1 + ang2) / 2;
                point tmp = p[i] + point(r * cos(md), r * sin(md));
                if(point_in_circle(tmp, p[j], r)){
                    t[cnt++] = node(ang1, 1);
                    t[cnt++] = node(ang2, -1);
                }
                else{
                    t[cnt++] = node(-Pi, 1);
                    t[cnt++] = node(ang1, -1);
                    t[cnt++] = node(ang2, 1);
                    t[cnt++] = node(Pi, -1);
                }
            }
        }
        sort(t, t + cnt);
        int cur = 0, mx = tot;
        for(int i = 0; i < cnt; ++i){
            cur += t[i].in;
            mx = max(mx, cur + tot);
        }
        ans = max(ans, mx);
    }

    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值