题目链接: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$

另一种方法:枚举两个点A,B,找到OA和AB中垂线的交点,这个交点就是圆心,计算圆心的众数即可,复杂度$O(n^2)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#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;
}