ACM 2018 南京区域赛 D - Country Meow (最小圆覆盖/三分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxxjxw/article/details/84203973

Gym 101981D

题目大意:

       宇宙中有n个城市,需要建一个指挥部,使得指挥部与所有城市之间的距离尽可能小。问指挥部和最远城市之间的最小欧几里得距离是多少。

题解:

     就是让球这n个点的最小球覆盖,指挥部是圆心,球的半径就是指挥部到最远城市之间的欧几里得距离

     红书上有板子,直接套就可以过了

     这么长的两页板子经常会漏掉一些,所以一定敲完之后查下错,不然敲完之后WA可还可能觉得是套板子不对......

     注意定义Tpoint的xyz类型应该用double,而不是int!!!

#include<bits/stdc++.h>
#include<cstring>
#define ll long long
#define INF 1000000007
#define eps 1e-6
#define mod 1000000007
#define double long double
using namespace std;
struct Tpoint
{
    double x,y,z;
};
int npoint,nouter;
Tpoint pt[200000],outer[4],res;
double radius,tmp;
inline double dist(Tpoint p1,Tpoint p2)
{
    double dx=p1.x-p2.x,dy=p1.y-p2.y,dz=p1.z-p2.z;
    return (dx*dx+dy*dy+dz*dz);
}
inline double dot(Tpoint p1,Tpoint p2)
{
    return p1.x*p2.x+p1.y*p2.y+p1.z*p2.z;
}
void ball()
{
    Tpoint q[3];
    double m[3][3],sol[3],L[3],det;
    int i,j;
    res.x=res.y=res.z=radius=0;
    switch(nouter)
    {
    case 1:
        res=outer[0];
        break;
    case 2:
        res.x=(outer[0].x+outer[1].x)/2;
        res.y=(outer[0].y+outer[1].y)/2;
        res.z=(outer[0].z+outer[1].z)/2;
        radius=dist(res,outer[0]);
        break;
    case 3:
        for(int i=0; i<2; ++i)
        {
            q[i].x=outer[i+1].x-outer[0].x;
            q[i].y=outer[i+1].y-outer[0].y;
            q[i].z=outer[i+1].z-outer[0].z;
        }
        for(int i=0; i<2; ++i)
            for(int j=0; j<2; ++j)
                m[i][j]=dot(q[i],q[j])*2;
        for(int i=0; i<2; ++i)
            sol[i]=dot(q[i],q[i]);
        if(fabs(det=m[0][0]*m[1][1]-m[0][1]*m[1][0])<eps)
            return;
        L[0]=(sol[0]*m[1][1]-sol[1]*m[0][1])/det;
        L[1]=(sol[1]*m[0][0]-sol[0]*m[1][0])/det;
        res.x=outer[0].x+q[0].x*L[0]+q[1].x*L[1];
        res.y=outer[0].y+q[0].y*L[0]+q[1].y*L[1];
        res.z=outer[0].z+q[0].z*L[0]+q[1].z*L[1];
        radius=dist(res,outer[0]);
        break;
    case 4:
        for(int i=0; i<3; ++i)
        {
            q[i].x=outer[i+1].x-outer[0].x;
            q[i].y=outer[i+1].y-outer[0].y;
            q[i].z=outer[i+1].z-outer[0].z;
            sol[i]=dot(q[i],q[i]);
        }
        for(int i=0; i<3; ++i)
            for(int j=0; j<3; ++j)
                m[i][j]=dot(q[i],q[j])*2;
        det=m[0][0]*m[1][1]*m[2][2]
            +m[0][1]*m[1][2]*m[2][0]
            +m[0][2]*m[2][1]*m[1][0]
            -m[0][2]*m[1][1]*m[2][0]
            -m[0][1]*m[1][0]*m[2][2]
            -m[0][0]*m[1][2]*m[2][1];
        if(fabs(det)<eps)return ;
        for(int j=0; j<3; ++j)
        {
            for(int i=0; i<3; ++i)
                m[i][j]=sol[i];
            L[j]=(m[0][0]*m[1][1]*m[2][2]
                  +m[0][1]*m[1][2]*m[2][0]
                  +m[0][2]*m[2][1]*m[1][0]
                  -m[0][2]*m[1][1]*m[2][0]
                  -m[0][1]*m[1][0]*m[2][2]
                  -m[0][0]*m[1][2]*m[2][1]
                 )/det;
            for(int i=0; i<3; ++i)
                m[i][j]=dot(q[i],q[j])*2;
        }
        res=outer[0];
        for(int i=0; i<3; ++i)
        {
            res.x+=q[i].x*L[i];
            res.y+=q[i].y*L[i];
            res.z+=q[i].z*L[i];
        }
        radius=dist(res,outer[0]);
    }
}
void minball(int n)
{
    ball();
    if(nouter<4)
    {
        for(int i=0; i<n; ++i)
            if(dist(res,pt[i])-radius>eps)
            {
                outer[nouter]=pt[i];
                ++nouter;
                minball(i);
                --nouter;
                if(i>0)
                {
                    Tpoint Tt=pt[i];
                    memmove(&pt[1],&pt[0],sizeof(Tpoint)*i);
                    pt[0]=Tt;
                }
            }
    }
}
double smallest_ball()
{
    radius=-1;
    for(int i=0; i<npoint; ++i)
    {
        if(dist(res,pt[i])-radius>eps)
        {
            nouter=1;
            outer[0]=pt[i];
            minball(i);
        }
    }
    return sqrt(radius);
}
int main()
{
    //freopen("input.txt","r",stdin);
    while(cin>>npoint)
    {
        for(int i=0; i<npoint; ++i)
        {
            cin>>pt[i].x>>pt[i].y>>pt[i].z;
        }
        cout<<fixed<<setprecision(15)<<smallest_ball()<<endl;
    }
    return 0;
}
/*
3
0 0 0
3 0 0
0 4 0
4
0 0 0
1 0 0
0 1 0
0 0 1
*/

猜你喜欢

转载自blog.csdn.net/hxxjxw/article/details/84203973
今日推荐