D - Deep800080

该博客主要探讨了一种寻找直线上的圆心,以覆盖最多点的算法问题。给定一条从(0,0)到(a,b)的直线和一系列点,通过计算点到直线的距离并找到与直线相切的圆,确定能够覆盖最多点的圆心位置。算法涉及到直线交点计算、点到直线距离以及圆与直线交点的求解,最后通过排序和计数确定最大覆盖数。
摘要由CSDN通过智能技术生成

题意
给你一条直线,直线两端点为(0,0)和(a,b),在直线上找一圆心,求能覆盖最多的点为多少
Sample input
7 5 0 1
-1 -1
1 -1
0 0
2 3
3 4
10 10
2 12
Sample output
5
看的是这位大佬的

#include <cstdio>
#include <iostream>
#include <cmath>
#include <utility>
#include <vector>
#include <algorithm>
#define eps 1e-8
#define N_MAX 300005
using std::pair;
int n,ans,res;
double r,a,b;
int sign(double x){
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    return 1;
}
struct Node{
    double x,y;
    int c;
    Node(double x = 0,double y = 0,int c = 0):x(x),y(y),c(c){}
};
bool cmp(Node _a,Node _b){
    if(sign(_a.x - _b.x) == 0 && sign(_a.y - _b.y) == 0 )return _a.c > _b.c;
    if(sign(_a.x - _b.x) == 0)return _a.y < _b.y;
    return _a.x < _b.x;
}
std::vector <Node> vec;
struct Point{
    double x,y;
    Point(double x = 0,double y = 0):x(x),y(y){}
    Point operator+(Point a){
        return Point(x + a.x,y + a.y);
    }
    Point operator-(Point a){
        return Point(x - a.x,y - a.y);
    }
    Point operator*(double t){
        return Point(x * t,y * t);
    }
    Point operator/(double t){
        return Point(x / t,y / t);
    }
    double cross(Point a){
        return x * a.y - a.x * y;
    }
    double dot(Point a){
        return a.x * x + a.y * y;
    }
    double lenth(){
        return sqrt(x * x + y * y);
    }
}point[N_MAX];
struct Line{
    Point a,b;
    Line(){}
    Line(Point a,Point b){
        this->a = a;
        this->b = b;
    }
}line;
Point GetPointForLine(Line X,Line Y){ // 算直线交点
    Point v = X.a - X.b;
    Point w = Y.a - Y.b;
    Point u = X.a - Y.a;
    double base = (w.cross(u)) / (v.cross(w));
    return X.a + v * base;
}
double DistanceForLine(Point P,Line X){ // 算点到直线的距离
    Point vp = X.b - X.a,vq = P - X.a;
    return fabs(vp.cross(vq))/vp.lenth();
}
pair<Point,Point> PointWithCircleAndLine(Point o,Line X){ // 求圆与直线的交点
    Point o2 = o;
    o2.x += X.a.y - X.b.y;
    o2.y += X.b.x - X.a.x;
    o2 = GetPointForLine(Line(o,o2),X);
    double base = sqrt(r * r - (o2 - o).lenth() * (o2 - o).lenth());
    Point e = (X.b - X.a) / (X.b - X.a).lenth();
    return std::make_pair(o2 - e * base,o2 + e * base);
}
int main(int argc,char *argv[]){
    scanf("%d %lf %lf %lf",&n,&r,&a,&b);
    line.a = Point(0,0);
    line.b = Point(a,b);
    for(int i = 1;i <= n;i++){
        scanf("%lf %lf",&point[i].x,&point[i].y);
        if(DistanceForLine(point[i],line) <= r){
            pair<Point,Point> q = PointWithCircleAndLine(point[i],line);
            Node p1 = Node(q.first.x,q.first.y,1);
            Node p2 = Node(q.second.x,q.second.y,-1);
            if(p1.x > p2.x){
                p1.c = -1;
                p2.c = 1;
            }
            else if(sign(p1.x - p2.x) == 0 && p1.y > p2.y){
                p1.c = -1;
                p2.c = 1;
            }
            vec.emplace_back(p1);
            vec.emplace_back(p2);
        }
    }
    std::sort(vec.begin(),vec.end(),cmp);
    for(auto i:vec){
        //printf("%.2lf %.2lf\n",i.x,i.y);
        res += i.c;
        ans = std::max(res,ans);
    }
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值