• 【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法


    【BZOJ1336】[Balkan2002]Alien最小圆覆盖

    Description

    给出N个点,让你画一个最小的包含所有点的圆。

    Input

    先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0)

    Output

    输出圆的半径,及圆心的坐标

    Sample Input

    6
    8.0 9.0
    4.0 7.5
    1.0 2.0
    5.1 8.7
    9.0 2.0
    4.5 1.0

    Sample Output

    5.00
    5.00 5.00

    题解:特地学了一发随机增量法,期望复杂度据说是O(n),但不会证。

    起初以1为圆心。先枚举一个点,如果这个点在圆外,则改为以哪个点为圆心;再枚举一个点,如果这个点再圆外,则圆心改为这两个点的中点;再枚举一个点,如果这个点再圆外,则将圆心改为三角形的内心。如何求内心?本人懒得推式子所以写的高斯消元。

    由于是期望复杂度所以一开始要将原序列随机排序。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int maxn=500010;
    const double eps=1e-12;
    struct point
    {
    	double x,y;
    	point() {}
    	point(double a,double b){x=a,y=b;}
    }p[maxn],O;
    int n;
    double v[10][10],R;
    point calc(point a,point b,point c)
    {
    	v[1][1]=2*b.x-2*a.x;
    	v[1][2]=2*b.y-2*a.y;
    	v[1][3]=b.x*b.x-a.x*a.x+b.y*b.y-a.y*a.y;
    	v[2][1]=2*c.x-2*b.x;
    	v[2][2]=2*c.y-2*b.y;
    	v[2][3]=c.x*c.x-b.x*b.x+c.y*c.y-b.y*b.y;
    	int i,j,k;
    	for(i=1;i<=2;i++)
    	{
    		for(j=i+1;j<=2;j++)	if(fabs(v[j][i])>fabs(v[i][i]))	for(k=i;k<=3;k++)	swap(v[i][k],v[j][k]);
    		double tmp=v[i][i];
    		for(k=i;k<=3;k++)	v[i][k]/=tmp;
    		for(j=1;j<=2;j++)	if(i!=j)	for(tmp=v[j][i],k=i;k<=3;k++)	v[j][k]-=tmp*v[i][k];
    	}
    	point ret(v[1][3],v[2][3]);
    	return	ret;
    }
    double dis(point a,point b)
    {
    	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    int main()
    {
    	scanf("%d",&n);
    	int i,j,k;
    	for(i=1;i<=n;i++)	scanf("%lf%lf",&p[i].x,&p[i].y);
    	random_shuffle(p+1,p+n+1);
    	O=p[1],R=0;
    	for(i=2;i<=n;i++)	if(dis(O,p[i])>R+eps)
    	{
    		O=p[i],R=0;
    		for(j=1;j<i;j++)	if(dis(O,p[j])>R+eps)
    		{
    			O=point((p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2),R=dis(O,p[i]);
    			for(k=1;k<j;k++)	if(dis(O,p[k])>R+eps)
    				O=calc(p[i],p[j],p[k]),R=dis(O,p[k]);
    		}
    	}
    	printf("%.2lf
    %.2lf %.2lf",R,O.x,O.y);
    	return 0;
    }
  • 相关阅读:
    一个表对应另一个表中多个主键的查询方法(把一个表当成两个表用)
    可以切换数据库的SqlHelper
    win7安装后的用户选择
    如何删除 Windows.old 文件夹
    Windows Server 2008磁盘清理工具
    sqlserver express版PRIMARY 大小不能超过4G
    一交换机,一光猫、一路由器组internet网的方法
    公司部门职责清晰
    IIS下载EXE(拾遗)
    win2008 IIS 7.0中WebDAV
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7452273.html
Copyright © 2020-2023  润新知