CCPC.2017哈尔滨站 M(判断三点共线+求三点外心+随机数)

题目链接:传送门

思路:
1、随机选择三个点,成功的概论未1/8,所以用随机数多试几次就可以;
2、判断三点共线+求三点外心模板,判断这个圆求判断是否有大于(n+1)/2个点的距离为r。
(相信自己的代码,多试几次)
代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const double eps = 1e-6;
struct Node
{
    double x,y;
}cur[N];
struct Circle
{
    Node pos;
    double r;
};
int n,T;
//判断三个点是否共线
bool gongxian(Node a,Node b,Node c)
{
    double Xba = (a.x - b.x),Yba = (a.y - b.y);
    double Xca = (a.x - c.x),Yca = (a.y - c.y);
    if(fabs(Xba*Yca - Xca*Yba) < eps) return true;
    return false;
}
double dis(Node a,Node b)
{
    return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
//三个点求外心
Node f(Node a,Node b,Node c)
{
    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;
    return Node{a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d};
}
int main(void)
{
    srand(29001);
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=1;i<=n;i++) cin>>cur[i].x>>cur[i].y;

        if(n == 1){
            printf("%f %f %f\n",cur[1].x,cur[1].y,0.0);
            continue;
        }
        else if(n <= 4){
            printf("%f %f %f\n",(cur[1].x + cur[2].x)/2,(cur[1].y + cur[2].y)/2,
                   dis(cur[1],cur[2])/2);
            continue;
        }

        Circle ans,tp;
        while(true){
            int t1 = rand()%n+1,t2 = rand()%n+1,t3 = rand()%n+1;
            if(t1 == t2 || t2 == t3 || t1 == t3 || gongxian(cur[t1],cur[t2],cur[t3])) continue;
            tp.pos = f(cur[t1],cur[t2],cur[t3]);
            tp.r = dis(tp.pos,cur[t1]);
            int cnt = 0;
            for(int i=1;i<=n;i++){
                if(fabs(dis(tp.pos,cur[i]) - tp.r) < eps) cnt++;
            }
            if(cnt >= (n+1)/2){
                ans = tp;break;
            }
        }
        printf("%f %f %f\n",ans.pos.x,ans.pos.y,ans.r);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值