题意:给你n个点,让你找到一个圆,输出圆心,和半径,使得有超过一半的点刚好在圆上.n<=1e5,题目保证了有解
题解:刚开始看着很不可做的样子,但是多想想,三点确定一个圆,三点啊!
现在有1/2的点都在圆上,意味着很多选出来的3个点都会导致同样的结果啊
我们同时可以说,每次随机一个点,这个点在圆上的概率为1/2,那任意三个点同时在圆上的概率就是1/8
所以我们随机来个几万次就好了啊!
注意的就是点数<=4的时候,1的时候输出自己就可以了,2,3,4的时候随便输出2个点的中点就行了
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct point 4 { 5 double x,y; 6 }a[100005],pp; 7 int T,n,x,y,z; 8 #define eps 1e-10 9 double R; 10 point cit(point a,point b,point c) 11 { 12 point cp; 13 double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2; 14 double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2; 15 double d=a1*b2-a2*b1; 16 cp.x=a.x+(c1*b2-c2*b1)/d; 17 cp.y=a.y+(a1*c2-a2*c1)/d; 18 return cp; 19 } 20 double dis(point a,point b) 21 { 22 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 23 } 24 int ok(point p) 25 { 26 int tot=0; 27 for (int i=1;i<=n;i++) 28 { 29 if (fabs(dis(p,a[i])-R)<eps) tot++; 30 if (tot>=(n+1)/2) return 1; 31 } 32 return 0; 33 } 34 int kk(point x,point y,point z) 35 { 36 if ((x.x-y.x)*(x.y-z.y)==(x.y-y.y)*(x.x-z.x)) return 1; 37 return 0; 38 } 39 int main() 40 { 41 srand(time(0)); 42 scanf("%d",&T); 43 while (T--) 44 { 45 scanf("%d",&n); 46 for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); 47 if (n==1) 48 { 49 printf("%lf %lf 0\n",a[1].x,a[1].y); 50 continue; 51 } 52 if (n<=4) 53 { 54 pp.x=(a[1].x+a[2].x)/2; 55 pp.y=(a[1].y+a[2].y)/2; 56 printf("%lf %lf %lf\n",pp.x,pp.y,dis(pp,a[1])); 57 continue; 58 } 59 for (int i=1;i<=5000000;i++) 60 { 61 x=rand()*rand()%n+1; 62 y=rand()*rand()%n+1; 63 z=rand()*rand()%n+1; 64 if (x==y || y==z || x==z) continue; 65 if (kk(a[x],a[y],a[z])) continue; 66 pp=cit(a[x],a[y],a[z]); 67 R=dis(pp,a[x]); 68 if (ok(pp)) 69 { 70 printf("%lf %lf %lf\n",pp.x,pp.y,R); 71 break; 72 } 73 } 74 } 75 }