2020牛客暑期多校训练营(第二场) B、Boundary (暴力枚举)

博客介绍了如何通过暴力枚举的方法解决寻找最多能经过多少个点的问题,给出了官方题解和作者自己的理解。通过枚举两点来确定可能的圆,并利用不在同一直线上的三点共圆的性质,确定圆心并计算点的数量。
摘要由CSDN通过智能技术生成

题目链接

题面:
在这里插入图片描述

题意:
给定n个点,对于一个过原点的圆,求出最多能经过多少个点。

官方题解:
在这里插入图片描述

我的题解:
两维枚举 i,j ,对于一个固定的 i 来说,看看后面有多少个点是共圆的。
不在一条直线上的三点可以确定一个圆。
( 0 , 0 ),p [ i ] , p [ j ] 即可确定一个圆,只需要记录这个圆的圆心即可(因为(0,0)点已经确定,一个圆心唯一确定一条半径)

剩下的就是板子啦。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x)  (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
using namespace std;

const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=2100;
const int maxm=100100;
const int up=100000;


//浮点型数值是否为0
int sgn(double x)
{
    if(abs(x)<eps) return 0;
    if(x<0) return -1;
    return 1;
}


//返回x的平方
double sqr(double x)
{
    return x*x;
}

//二维点
struct Point
{
    double  x,y;
    Point(){}
    Point(double xx,double yy)
    {
        x=xx,y=yy;
    }

    //输入输出
    void input(void)
    {
        scanf("%lf%lf",&x,&y);
    }
    void output(void)
    {
        printf("%.2f %.2f\n",x,y);
    }

    //重载比较运算符
    bool operator == (const Point &b) const
    {
        return sgn(x-b.x)==0&&sgn(y-b.y)==0;
    }

    bool operator < (const Point &b) const
    {
        if(sgn(x-b.x)!=0) return x<b.x;
        else return sgn(y-b.y)<0;
    }

    //重载加减乘除
    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);
    }

    //叉乘,叉积
    double operator ^ (const Point &b) const
    {
        return x*b.y-y*b.x;
    }
    //点乘,点积
    double operator * (const Point &b) const
    {
        return x*b.x+y*b.y;
    }

    //两点距离
    double dis(const Point &b) const
    {
        return hypot(x-b.x,y-b.y);
    }

    //逆时针转90
    Point turn_left(void)
    {
        return Point(-y,x);
    }

};

//****************************************************************
//****************************************************************

struct Line
{
    Point s,e;
    Line(){}

    //两点
    Line(const Point ss,const Point ee)
    {
        s=ss,e=ee;
    }
    //点和直线的关系
    //1 在左侧 (在s——>e的逆时针侧)
    //2 在右侧 (在s——>e的顺时针侧)
    //3 在直线上
    int relation(const Point &p)
    {
        int c=sgn((p-s)^(e-s));
        if(c<0) return 1;
        else if(c>0) return 2;
        else return 3;
    }


    //求两直线的交点
    //要保证两直线不平行或重合
    Point cross_point(Line v)
    {
        double a1=(v.e-v.s)^(s-v.s);
        double a2=(v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }

};



struct circle
{
    Point p;
    double r;
    circle(){}
    circle(double xx,double yy,double rr)
    {
        p=Point(xx,yy);
        r=rr;
    }
    //三角形外接圆
    //利用两条边的中垂线得到圆心
    circle(Point a,Point b,Point c)
    {
        Line u=Line((a+b)/2,((a+b)/2)+((b-a).turn_left()));
        Line v=Line((b+c)/2,((b+c)/2)+((c-b).turn_left()));
        p=u.cross_point(v);
        r=p.dis(a);
    }

};

Point p[maxn];
Point zero=Point(0.0,0.0);
map<Point,int>mp;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        p[i].input();
    int ans=1;
    circle now;
    for(int i=1;i<=n;i++)
    {
        mp.clear();
        for(int j=i+1;j<=n;j++)
        {
            if(Line(p[i],p[j]).relation(zero)==3) continue;
            now=circle(p[i],p[j],zero);
            mp[now.p]++;
            ans=max(ans,mp[now.p]+1);
        }
    }
    printf("%d\n",ans);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值