题意:
给了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;
}

京公网安备 11010502036488号