M - Geometry Problem HDU - 6242

Geometry Problem

https://vjudge.net/contest/253412#problem/M

题意:给你n个点,让你找出一个点让至少存在n/2个点到这个点的距离为r,输出点的坐标和r。

思路:这个题目中点的个数为1e5,比赛的时候一直都不知道该怎么做,一点思路都没有,感觉不管枚举什么复杂度都很高,赛后才知道这个可以用随机程序完成这个题目,平时也没有怎么做过随机数的题目。我们可以随机枚举三个点,然后通过三个点确定一个圆,确定出圆的圆心,在判断这个圆是否满足要求即可,在求三角形外接圆的时候,可以通过距离方程完成,设圆心的坐标,三个点到圆心的距离相同,解方程即可。 

#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+50;
struct Point
{
    double x,y;
    Point() {}
    Point (double a,double b)
    {
        x=a;
        y=b;
    }
} p[maxn];
double dis(int a,int b)
{
    return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y));
}
Point heart(int a,int b,int c)
{
    double a1=p[b].x-p[a].x;
    double b1=p[b].y-p[a].y;
    double c1=(p[b].x*p[b].x+p[b].y*p[b].y-p[a].x*p[a].x-p[a].y*p[a].y)/2;

    double a2=p[c].x-p[b].x;
    double b2=p[c].y-p[b].y;
    double c2=(p[c].x*p[c].x+p[c].y*p[c].y-p[b].x*p[b].x-p[b].y*p[b].y)/2;
    double  x=(b2*c1-b1*c2)/(a1*b2-a2*b1);
    double y=(c1*a2-a1*c2)/(b1*a2-a1*b2);
    return Point(x,y);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        if(n==1||n==2)
        {
            printf("%lf %lf %lf\n",p[0].x+1,p[0].y,1.0);
        }
        else if(n==3||n==4)
        {
            printf("%lf %lf %lf\n",(p[0].x+p[1].x)/2,(p[0].y+p[1].y)/2,dis(0,1)/2);
        }
        else
        {
            while(1)
            {
                int a=rand()%n;
                int b=rand()%n;
                int c=rand()%n;
                if(a==b||a==c||b==c) continue;
                if(fabs((p[b].y-p[a].y)*(p[c].x-p[b].x)-(p[c].y-p[b].y)*(p[b].x-p[a].x))<=1e-6)continue;
                Point h=heart(a,b,c);


                int sum=0;
                p[n].x=h.x;
                p[n].y=h.y;
                for(int i=0; i<n; i++)
                {
                    if(fabs(dis(n,i)-dis(n,a))<1e-6) sum++;
                }
                if(sum*2>=n)
                {
                    printf("%lf %lf %lf\n",h.x,h.y,dis(n,a));
                    break;
                }
            }

        }
    }
//    cout << "Hello world!" << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值