题目点击这里
给你一个二维平面外加n(n<2000)个点,问你最多能找到几个点和原点(0,0)共圆。
错误思路:一开始是想先枚举一个点为直径,再找剩下的点中能直径形成直角的点。但是共圆的点不一定一定要存在着能形成直径的点,因此考虑不全。
正确做法:
1.可以向题解一样用圆周角来找
2.通过任意找两点,分别连接他们与原点,然后再在连接的直线上做中垂线,两条中垂线的交点即为圆心,最后判断哪个点成为圆心的次数最多即为我们所找的原,然后在判断最多可以从多大的n中(也就是我们最后求得答案)找两个点来满足要求。
找圆心的过程就是求解方程组:
参考:https://blog.csdn.net/weixin_43269437/article/details/107327887?%3E
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e3+7;
vector< pair<int,int> >P;//点
vector< pair<double,double> >C;//可能的圆心
ll getD(ll a,ll b,ll c,ll d){
return a*d-b*c;
}
int main()
{
int n;
P.resize(2007);
scanf("%d",&n);
int x,y;
for(int i = 1;i <= n;i ++){
scanf("%d%d",&x,&y);
P[i] = make_pair(x,y);//存对用make_pair
}
for(int i = 1;i <= n-1;i ++){
for(int j = i+1;j <= n;j ++){
int x1 = P[i].first,y1 = P[i].second;
int x2 = P[j].first,y2 = P[j].second;
// 克拉默法则解方程组
ll a11 = 2*x1,a12 = 2*y1,b1 = x1*x1+y1*y1;
ll a21 = 2*x2,a22 = 2*y2,b2 = x2*x2+y2*y2;
ll D = getD(a11,a12,a21,a22);
if(D == 0) continue;
ll D1 = getD(b1,a12,b2,a22);
ll D2 = getD(a11,b1,a21,b2);
//printf("%d %d %d\n",D,D1,D2);
C.push_back(make_pair((double)D1/D , (double)D2/D ));//圆心可能的解
}
}
sort(C.begin(),C.end());
int maxx = 0;
for(int i = 0;i < C.size();){
int j = i;
while(j < C.size()&&C[j] == C[i]) j++;
maxx = max(maxx,j-i);
i = j;
}
//cout<<maxx<<endl;
int ans = 0;
for(int i = 1;i < MAXN;i ++){
if((i-1)*i/2 <= maxx)//这个n可能是合法的点的个数
ans = max(ans,i);
}
printf("%d\n",ans);
return 0;
}