2020牛客暑期多校训练营(第二场)B.Boundary

2020牛客暑期多校训练营(第二场)B.Boundary

题目链接

题目描述

Given n {n} n points in 2D plane. Considering all circles that the origin point ( 0 , 0 ) {(0, 0)} (0,0) is on their boundries, find the one with the maximum given points on its boundry. Print the maximum number of points.

输入描述:

The first line contains one integer n   ( 1 ≤ n ≤ 2000 ) n~(1 \leq n \leq 2000) n (1n2000), denoting the number of given points.
Following {n}n lines each contains two integers x , y   ( ∣ x ∣ , ∣ y ∣ ≤ 10000 ) x, y~(|x|,|y| \leq 10000) x,y (x,y10000), denoting a given point ( x , y ) {(x, y)} (x,y).
It’s guaranteed that the points are pairwise different and no given point is the origin point.

输出描述:

Only one line containing one integer, denoting the answer.

示例1

输入

4
1 1
0 2
2 0
2 2

输出

3

1.题解做法:
2020牛客暑期多校训练营(第二场)B.Boundary_第1张图片
题解很容易懂,做起来很容易错
1.判断角度的个数不能直接用 m a p map map,会有精度问题,只能过 65%
2.如果存每一个角度判断还是有精度问题,此时离成功只差一步之遥了,能过 90%,那就是必须要 1 e − 10 1e^{-10} 1e10 的精度
求角度直接套的板子,判断向量的方向直接用叉积即可,AC代码如下:

#include
using namespace std;
typedef long long ll;
const int N=2e3+5;
double ang[N*N],eps=1e-10;
struct point{
    double x,y;
}p[N];

double cross(point a,point b,point c){
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}

double angle(point o,point s,point e)
{
     double cosfi,fi,norm;
     double dsx = s.x - o.x;
     double dsy = s.y - o.y;
     double dex = e.x - o.x;
     double dey = e.y - o.y;
     cosfi=dsx*dex+dsy*dey;
     norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey);
     cosfi /= sqrt( norm );
     if (cosfi >=  1.0 ) return 0;
     if (cosfi <= -1.0 ) return -3.1415926;
     fi=acos(cosfi);
     if (dsx*dey-dsy*dex>0) return fi; 
     return -fi;
}

int main(){
    int n,ans=0;
    point p0;
    p0.x=p0.y=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    for(int i=0;i<n;i++){
        int sum=0,cnt=0;
        for(int j=0;j<n;j++){
            if(i==j) continue;
            if(cross(p[i],p[j],p0)<0) ang[cnt++]=angle(p[j],p[i],p0);
        }
        sort(ang,ang+cnt);
        double ANG=eps;
        for(int i=0;i<cnt;i++){
            if(fabs(ang[i]-ANG)<eps) sum++;
            else{
                ANG=ang[i];
                sum=1;
            }
            ans=max(ans,sum);
        }
    }
    printf("%d",ans+1);
    return 0;
}

2.圆心公式,直接枚举两个点与圆点求圆心,圆心最多的就是答案,圆心公式直接套的板子,也可以手推,AC代码如下:

#include
using namespace std;
const int N=2e3+5;
double eps=1e-10;
map<pair<double,double>,int>m;
struct point{
    double x,y;
}p[N];
double X,Y;
void Circle_center(point p1,point p2,point p3){
    double a = p1.x - p2.x;
    double b = p1.y - p2.y;
    double c = p1.x - p3.x;
    double d = p1.y - p3.y;
    double e = ((p1.x * p1.x - p2.x * p2.x) + (p1.y * p1.y - p2.y * p2.y)) / 2.0;
    double f = ((p1.x * p1.x - p3.x * p3.x) + (p1.y * p1.y - p3.y * p3.y)) / 2.0;
    double det = b * c - a * d;
    if (fabs(det) < eps) {
        X=Y=0;
        return ;
    }
    X = -(d * e - b * f) / det;
    Y = -(a * f - c * e) / det;
    return ;
}

int main(){
    int n,ans=0;
    point p0;
    p0.x=p0.y=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    for(int i=0;i<n;i++){
        m.clear();
        for(int j=i+1;j<n;j++){
            if((p[i].x*p[j].y-p[j].x*p[i].y)==0) continue;
            Circle_center(p0,p[i],p[j]);
            m[{X,Y}]++;
            ans=max(ans,m[{X,Y}]);
        }
    }
    printf("%d",ans+1);
    return 0;
}

你可能感兴趣的:(计算几何,思维,牛客)