很神奇的一道题,随机数大法
给出n个点,要求一个圆心和半径,让不少于n/2的点在圆上,保证有这样的解,每个点在这样圆上的概率是1/2
可以随机选三个点定位它们的圆心,那么这个圆心是我们要找的圆心的概率为1/8
所以我们就不断地随机选三个点,求出圆心,再判断经过这个圆的点是否足够就可以了
时间复杂度O(n*t),t多大看运气,只要运气不太差不会TLE
还有n<=4时要特判,n==1时圆心就自己定,2<=n<=4时只要选两个点的中心作为圆心就可以
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
using namespace std;
typedef long long ll;
const int N=1e5+10;
//Point定义
const double eps=1e-6;
const double PI=acos(-1.0);
inline int sgn(double x)
{
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y)
{
x=_x;y=_y;
}
Point operator - (const Point &b) const
{
return Point(x-b.x,y-b.y);
}
//叉积
double operator ^ (const Point &b) const
{
return x*b.y-y*b.x;
}
//点积
double operator * (const Point &b) const
{
return x*b.x+y*b.y;
}
///绕原点旋转角度B(弧度值),后x,y的变化
void transXY(double B)
{
double tx=x,ty=y;
x=tx*cos(B)-ty*sin(B);
y=tx*sin(B)+ty*cos(B);
}
};
//两点间距离
double dist(Point a,Point b)
{
return sqrt((a-b)*(a-b));
}
//过三点求圆心坐标
Point waixin(Point a,Point b,Point c)
{
double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
double d=a1*b2-a2*b1;
return Point(a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d);
}
int n;
Point a[N];
int main()
{
int T;
srand(time(NULL));
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
if(n==1)
{
printf("%f %f %f\n",a[0].x+1,a[0].y,1.0);
continue;
}
if(n<=4)
{
printf("%f %f %f\n",(a[0].x+a[1].x)/2.0,(a[0].y+a[1].y)/2.0,dist(a[0],a[1])/2.0);
continue;
}
int cnt=n/2;
if(n%2) cnt++;
while(true)
{
int p1,p2,p3;
p1=rand()%n;
p2=rand()%n;
while(p1==p2) p2=rand()%n;
p3=rand()%n;
while(p1==p3||p2==p3) p3=rand()%n;
Point O=waixin(a[p1],a[p2],a[p3]);
double R=dist(a[p1],O);
if(abs(O.x)>1e9||abs(O.y)>1e9||R>1e9) continue;
int num=0;
for(int i=0;i<n;i++)
if(fabs(dist(a[i],O)-R)<eps) num++;
if(num>=cnt)
{
printf("%f %f %f\n",O.x,O.y,R);
break;
}
}
}
return 0;
}