【BZOJ2823】【AHOI2012】信号塔 最小圆覆盖 计算几何

链接:

#include 
int main()
{
    puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/46605193");
}

题解之前:

首先最小圆覆盖虽然有三层 for 循环,但是它是期望 O(n) 的。什么?你问我为啥?那我只能呵呵了,50W的 O(n3) 高速跑过。
实测
后交的是不求凸包直接跑的,先交的是求了凸包再跑的。。并没有什么差距。

题解:

这道题我们可以先写一份求凸包来缩减点的规模,如果点是随机生成的,那么期望有不到100个点在凸包上,然后就可以乱搞了(其实毛用没有2333)

然后这道题需要用到 [最小圆覆盖] (呃其实这道题就是裸的最小圆覆盖……)

最小圆覆盖:

初始圆为 点 1 这个半径为 0 的圆。。
for1ni=2 i 不在已有圆中,则求一个圆周包含 i 的最小圆。
{
       圆改为点 i 这个半径为 0 的圆
       for2i1j=1 j 不在已有圆中,则求一个圆周包含 ij 的最小圆。
       {
             圆改为以线段 (i,j) 为直径的圆
             for2j1k=1 k 不在已有圆中,则求一个圆周包含 ijk 的最小圆。
             {
                   圆改为三角形 (i,j,k) 的外接圆
             }
       }
}
返回圆

真是奇葩。QwQ

代码:

那个求三角形外心不妨自己乱搞,这里的那个是懒得推直接扒的,然后没看懂QwQ

#include 
#include 
#include 
#include 
#define N 501000
#define eps 1e-7
using namespace std;
struct Point
{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    void read(){scanf("%lf%lf",&x,&y);}
    bool operator < (const Point &A)const
    {return fabs(x-A.x)double operator - (const Point &A)const
    {return sqrt((x-A.x)*(x-A.x)+(y-A.y)*(y-A.y));}
    void print(){printf("%.2lf %.2lf ",x,y);}
}p[N];
struct Circle
{
    Point c; // center
    double r;
    Circle(Point _c=Point(0,0),double _r=0):c(_c),r(_r){}
    bool operator ^ (const Point &A)const{return A-c>r+eps;} // 包含
    void print()
    {
        c.print();
        printf("%.2lf\n",r);
    }
};
inline double xmul(const Point &A,const Point &B,const Point &C)
{return (C.y-A.y)*(B.x-A.x)-(B.y-A.y)*(C.x-A.x);}
struct Get_Convex_Hull
{//求凸包
    int stk1[N],top1,stk2[N],top2;
    Point tp[N];
    void work(Point *p,int &n)
    {
        int i;
        sort(p+1,p+n+1);

        stk1[top1=1]=1;
        for(i=2;i<=n;i++)
        {
            while(top1>1&&xmul(p[stk1[top1-1]],p[stk1[top1]],p[i])>-eps)top1--;
            stk1[++top1]=i;
        }
        stk2[top2=1]=n;
        for(i=n-1;i;i--)
        {
            while(top2>1&&xmul(p[stk2[top2-1]],p[stk2[top2]],p[i])>-eps)top2--;
            stk2[++top2]=i;
        }
        n=0;
        for(i=1;ifor(i=1;ifor(i=1;i<=n;i++)p[i]=tp[i];
    }
}gch;
struct Get_Min_Circle_Cover
{
    Point circumcenter(const Point &a,const Point &b,const Point &c)
    {//返回三角形的外心 我并不知道这是什么鬼。。好强的样子。
        Point ret;
        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;
        ret.x=a.x+(c1*b2-c2*b1)/d;
        ret.y=a.y+(a1*c2-a2*c1)/d;
        return ret;
    }
    Circle work(int n)
    {
        random_shuffle(p+1,p+n+1);
        Circle C=Circle(p[1],0);
        int i,j,k;

        for(i=2;i<=n;i++)if(C^p[i])
        {
            C=Circle(p[i],0);
            for(j=1;jif(C^p[j])
            {
                C.c=Point((p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2);
                C.r=p[j]-C.c;
                for(k=1;kif(C^p[k])//求外接圆圆心,要求三点不能共线 
                    C.c=circumcenter(p[i],p[j],p[k]),C.r=C.c-p[i];

            }
        }
        return C;
    }
}gmcc;

int main()
{
//  freopen("test.in","r",stdin);

    int i=0,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++)p[i].read();
//  gch.work(p,n);
    Circle ret=gmcc.work(n);
    ret.print();

    return 0;
}

你可能感兴趣的:(最小圆覆盖,计算几何,BZOJ2823,AHOI2012,信号塔,最小圆覆盖,计算几何)