题意:
给了n个点,让你自己随便定义圆心(圆心不要求是n个点的其中一个)和半径,要求这n个点有尽可能多的点在圆上,并且该圆经过坐标原点(0,0)。求满足的圆上的点最多有多少个。
思路:
n是2e3,复杂度应该要小于n^3。我们知道最少三点可以确定一个圆。因为圆要求经过原点(0,0),所以考虑n^2枚举两个点,这样子就有三个点了,计算出三个点形成的圆的圆心坐标(注意三点共线的情况 那么肯定不存在圆 使得三点在一个圆上)
用vector保存下来这些圆心坐标。
处理完后,对圆心坐标sort一下,判断有多少个圆心坐标是一样的。
刚开始写的是map<pair<double,double>,int> 去存 ,一直TLE,只能过70%数据,所以就直接sort计算相同个数了
如果vector中,圆心个数为0,也就是所有点都在一条线上,那么直接输出1
因为两点可以确定无数个圆,选n个点中的一个都能和坐标原点形成任意一个圆
否则,在暴力枚举的两个点中,我们是组合数进行选取的,也就是n个点选取2个
其中ma是指出现最多的圆心坐标的次数
那么直接枚举1到n满足上述式子的就是答案
#include <bits/stdc++.h> using namespace std; double X, Y; struct Point { double x, y; } a[2005]; void solve(Point a, Point b, Point c) //三点共圆圆心公式 { double fm1=2 * (a.y - c.y) * (a.x - b.x) - 2 * (a.y - b.y) * (a.x - c.x); double fm2=2 * (a.y - b.y) * (a.x - c.x) - 2 * (a.y - c.y) * (a.x - b.x); if (fm1 == 0 || fm2 == 0) { X = Y = 1e18; return; } double fz1=a.x * a.x - b.x * b.x + a.y * a.y - b.y * b.y; double fz2=a.x * a.x - c.x * c.x + a.y * a.y - c.y * c.y; X = (fz1 * (a.y - c.y) - fz2 * (a.y - b.y)) / fm1; Y = (fz1 * (a.x - c.x) - fz2 * (a.x - b.x)) / fm2; } vector<pair<double,double>> mp; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &a[i].x, &a[i].y); for (int i = 1; i <= n; i++){ for (int j = i + 1; j <= n; j++){ solve({0, 0}, a[i], a[j]); if (X == Y && fabs(X - 1e18) < 1e-8) continue; mp.push_back({X,Y}); } } if(mp.size()==0){ putchar('1'); return 0; } sort(mp.begin(),mp.end()); int ma = 1; int num = 1; pair<double,double> now=mp[0]; for(int i=1;i<mp.size();i++){ if(mp[i]==now) ++num; else{ now=mp[i]; ma=max(ma,num); num=1; } ma=max(ma,num); } for (int i = 1; i <= n; i++){ if (i * (i - 1) == ma * 2){ printf("%d", i); return 0; } } return 0; }