1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第二場)B - Boundary

2020牛客暑期多校訓練營(第二場)B - Boundary

題目連結:Boundary

題意:給你n個點,問最多有多少個點與原點(0,0)在同一個圓上

思路:由於三點確定一個圓,所以如果列舉剩餘的兩個點,然後再列舉其他點是否在圓上,那麼複雜度為$O(n^3)$,會TLE

但我們可以利用$“$同弧所對的圓周角相等$”$這一性質,所以可以先列舉一個點P,然後列舉其他的點A,計算$\angle OAP$,找到這些角里面角的眾數即可,但是角相等只能說明弧相等,並不能保證這兩段弧為同一段弧,例如下圖,$\angle OA_{1}P=\angle OA_{2}P$,但這兩段弧並不是同一段弧

我們只需要計算一邊,所以用叉積來判斷即可,既滿足$\vec{OP}\times \vec{OA}<0$或者$\vec{OP}\times \vec{OA}>0$

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

const int N = 2010;
const double eps = 1e-10;

struct Vector {
    double x, y;
    Vector() { }
    Vector(double tx, double ty) : x(tx), y(ty) { }
};

int n; pair<double, double> p[N]; double a[N], t; inline double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; } inline double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; } inline double calc(Vector a, Vector b) { double la = sqrt(a.x * a.x + a.y * a.y);
double lb = sqrt(b.x * b.x + b.y * b.y); return acos(dot(a, b) / (la * lb)); } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].first, &p[i].second); int res = 0, cnt = 0; for (int i = 1; i <= n; i++) { cnt = 0; for (int k = 1; k <= n; k++) { Vector op = Vector(p[i].first, p[i].second); Vector oa = Vector(p[k].first, p[k].second); Vector ap = Vector(p[k].first - p[i].first, p[k].second - p[i].second); Vector ao = Vector(p[k].first, p[k].second); if (cross(op, oa) < 0) a[++cnt] = calc(ap, ao); } sort(a + 1, a + cnt + 1); int imax = 0, c = 0; for (int i = 1; i <= cnt; i++) { if (fabs(a[i] - t) < eps) c++; else { c = 1; t = a[i]; } imax = max(imax, c); } res = max(imax, res); } printf("%d\n", res + 1); return 0; }