Boundary 2020牛客多校第二场 (计算几何)

原题题面

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 ( 1 ≤ n ≤ 2000 ) (1≤n≤2000) (1n2000), denoting the number of given points.
Following {n}n lines each contains two integers x, y$ (∣x∣,∣y∣≤10000)$, 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.

输入样例

4
1 1
0 2
2 0
2 2

输出样例

3

题面解析

首先很容易就能想到 O ( n 3 ) O(n^3) O(n3)的暴力方法,但显然会超时。
先放出题人的方法,出题人给出了圆周角的方法计算(下图)
Boundary 2020牛客多校第二场 (计算几何)_第1张图片
笔者自己实际去尝试了以下,发现有部分细节并未说清楚(多个点平行时的处理),故不提供该种解法的代码。
笔者采用中垂线的办法去计算。
先算枚举两个点做两条中垂线,算完交点后取出最多的那个就是答案。
所以只要两重循环开 O ( n 2 ) O(n^2) O(n2)的复杂度去枚举点,然后用pair和map存下每个点出现的次数并比较即可。
需要注意的是,这题似乎卡了精度,貌似1e-10是可以的,读者可以自行尝试。

AC代码(345ms)

#include
using namespace std;
double eps=1e-10;
typedef pair<double, double> Pair;
int epsCmp(double x, double y)//误差范围内相等
{
    if (fabs(x-y)<eps)
        return 0;
    if (x>y)
        return 1;
    return -1;
}
struct point
{
    double x;
    double y;
};
struct line//ax+by+c=0
{
    double a;
    double b;
    double c;
};
point points[2010];
map<Pair,long long> hashMap;
void solve1()
{
    int t;
    scanf("%d", &t);
    for(int i=1; i<=t; i++)
    {
        scanf("%lf %lf", &points[i].x, &points[i].y);
    }
    long long ans=0;//初值不能是1,因为可能会出现n=1的情况
    for(int i=1; i<=t-1; i++)
    {
        hashMap.clear();
        for(int j=i+1; j<=t; j++)
        {
            point O=point{0.0, 0.0};//原点
            point P=point{points[i].x, points[i].y};//第一个枚举点P
            point A=point{points[j].x, points[j].y};//第二个枚举点A
            line OP=line{P.x, P.y, -(P.x*P.x+P.y*P.y)/2.0};//OP中垂线
            line OA=line{A.x, A.y, -(A.x*A.x+A.y*A.y)/2.0};//OA中垂线
            if (epsCmp(AP.a*OP.b, AP.b*OP.a)!=0)//排除平行情况
            {
                double x0=(OP.b*AP.c-OP.c*AP.b)/(OP.a*AP.b-OP.b*AP.a);
                double y0=(OP.a*AP.c-OP.c*AP.a)/(OP.a*AP.b-OP.b*AP.a);
                ans=max(ans, ++hashMap[Pair(x0,y0)]);//比较结果
            }
        }
    }
    printf("%lld\n", ans+1);//有n个圆形相同就有n+1个点被覆盖
}
int main()
{
//    ios_base::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long long test_index_for_debug=1;
    char acm_local_for_debug;
    while(cin>>acm_local_for_debug)
    {
        cin.putback(acm_local_for_debug);
        if (test_index_for_debug>100)
        {
            throw runtime_error("Check the stdin!!!");
        }
        auto start_clock_for_debug=clock();
        solve1();
        auto end_clock_for_debug=clock();
        cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
        cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
            <<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
        cout<<"--------------------------------------------------"<<endl;
    }
#else
    solve1();
#endif
    return 0;
}

后记

赛后被学弟带飞,不愧是后浪拍死前浪…
DrGilbert 2020.7.13

你可能感兴趣的:(计算几何)