「2017CCPC哈爾濱站 M」Geometry Problem【計算幾何】

題目鏈接

題意

  • 就是給你nn個點,然後讓你求一個圓,使得至少有n2\lceil \frac{n}{2}\rceil個點在圓上

題解

  • 由於至少有一半的點在圓上,又因爲三個不再同一條直線上的點可以確定一個圓,那麼考慮隨機出這三個點,然後O(n)O(n)checkcheck所有點是否在圓上,由於三個點都在構成答案的點集中的概率爲18\frac{1}{8},所以期望隨機次數爲88即可得到答案
  • 打虛擬賽的時候由於最後纔想起來隨機,忘記特判n4n\leq4的情況導致一直隨機而TLETLE,然後交了一發比賽就結束了QWQQWQ

複雜度

  • O(n)O(n)

代碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
#define eps 1e-4
#define pi acos(-1.0)
int sgn(double k) {return k<-eps?-1:(k<eps?0:1);}
struct point{
    double x,y;
    point(double a=0,double b=0) {x=a;y=b;}
    point operator*(double k) {return point(x*k,y*k);}
    double operator*(point other) {return x*other.x+y*other.y;}
    double operator^(point other) {return x*other.y-y*other.x;}
    point operator/(double k) {return point(x/k,y/k);}
    point operator+(point other) {return point(x+other.x,y+other.y);}
    point operator-(point other) {return point(x-other.x,y-other.y);}
    friend double len(point p) {return sqrt(p.x*p.x+p.y*p.y);}
    friend point rotate(point p1,point p2,double a) {
        point vec=p2-p1;
        double xx=vec.x*cos(a)+vec.y*sin(a);
        double yy=vec.y*cos(a)-vec.x*sin(a);
        return point(p1.x+xx,p1.y+yy);
    }
}p[maxn];
struct line{
    point s,e;
    line(){}
    line(point a,point b) {s=a;e=b;}
    friend point intersect(line l1,line l2) {
        double k=((l2.e-l2.s)^(l2.s-l1.s)/((l2.e-l2.s)^(l1.e-l1.s)));
        return l1.s+(l1.e-l1.s)*k;
    }
};
struct circle{
    point o;
    double r;
    circle() {}
    circle(point a,point b,point c) {
        point p1=rotate((a+b)/2,b,3*pi/2),p2=rotate((b+c)/2,c,3*pi/2);
        o=intersect(line((a+b)/2,p1),line((b+c)/2,p2));
        r=len(o-a);
    }
};

int n;
int main() {
    srand(998244353);
    int t;scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lf %lf",&p[i].x,&p[i].y);
        circle res;
        if(n==1) {
            printf("%.10lf %.10lf %.10lf\n",p[1].x,p[1].y,0);
            continue;
        }
        else if(n<=4) {
            printf("%.10lf %.10lf %.10lf\n",(p[1].x+p[2].x)/2,(p[1].y+p[2].y)/2,len(p[2]-p[1])/2);
            continue;
        }
        for(;;) {
            int x=rand()%n+1,y=rand()%n+1,z=rand()%n+1;
            if(x==y||x==z||y==z||(sgn((p[y]-p[x])^(p[z]-p[x]))==0)) continue;
            circle o=circle(p[x],p[y],p[z]);
            int cnt=0;
            for(int i=1;i<=n;i++) if(sgn(o.r-len(p[i]-o.o))==0) cnt++;
            if(cnt>=(n+1)/2 &&fabs(o.o.x)<=1e9 &&fabs(o.o.y)<=1e9 &&fabs(o.r)<1e9) {res=o;break;}
        }
        printf("%.10lf %.10lf %.10lf\n",res.o.x,res.o.y,res.r);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章