BZOJ 1336 & 1337 最小圆覆盖

来源:互联网 发布:shopnc java 源码 编辑:程序博客网 时间:2024/05/17 06:49

随即增量法

详见百度

枚举i,j,k,看上去是O(n^3)的,实际上因为数据随机,期望复杂度是O(n)的

枚举到不在圆内的i,即可知i必在【前i】覆盖圆的边上
继续枚举j,枚举到不在圆内的j,即可知j必在【i和前j】的覆盖圆上
继续枚举k,枚举到不在圆内的k,即可知k必在【i,j,前k】的覆盖圆上,此时三点定圆。

这样总能枚举到正确的圆上三点。

数据里应该没有奇怪的情况,所以没有被卡- -

#include<cstdio>#include<cmath>#include<algorithm>#define N 100005using namespace std;struct Point{    double x, y;}p[N];double dis(Point a, Point b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}const double eps = 1e-10;Point make_circle(Point p1, Point p2, Point p3){    double a = p1.x-p2.x, b = p1.y-p2.y, c = 0.5*(p1.x*p1.x-p2.x*p2.x-p2.y*p2.y+p1.y*p1.y);    double d = p1.x-p3.x, e = p1.y-p3.y, f = 0.5*(p1.x*p1.x-p3.x*p3.x-p3.y*p3.y+p1.y*p1.y);    double x = (c-f*b/e)/(a-b*d/e);    double y = (c-x*a)/b;    return (Point){x,y};}int main(){    int n;    scanf("%d",&n);    for(int i = 1; i <= n; i++)    {        scanf("%lf%lf",&p[i].x,&p[i].y);//      反正数据不卡我23333 //      p[i].x+=eps*(rand()%10+1);//      p[i].y+=eps*(rand()%10+1);    }    random_shuffle(p+1,p+1+n);    Point c=p[1];    double r=0;    for(int i = 2; i <= n; i++)    {        if(dis(c,p[i])>r)        {            c=p[i];            r=0;            for(int j = 1; j < i; j++)            {                if(dis(c,p[j])>r)                {                    c.x=(p[i].x+p[j].x)/2;                    c.y=(p[i].y+p[j].y)/2;                    r=dis(c,p[j]);                    for(int k = 1; k < j; k++)                    {                        if(dis(c,p[k])>r)                        {                            c=make_circle(p[i],p[j],p[k]);                             r=dis(c,p[k]);                        }                    }                }            }        }    }    printf("%.3lf\n",r);} 
0 0
原创粉丝点击