CodeForces 274C|275E|The Last Hole!|计算几何

本文介绍了一种算法,用于计算平面几何中多个圆逐渐扩大时,最后出现的“洞”消失的时间。通过枚举三角形和正方形来确定可能的洞,并使用三角形的外心概念来找出洞消失的具体位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出N个点,从零时刻起,分别以这N个点为圆心的N个圆逐渐变大,有半径r=时刻t;随着时间推移,图形当中可能出现一些”洞”,而且出现的洞一定会在某时刻消失。严格地,一个洞被定义为封闭的、连通的未被圆覆盖的区域,可以理解为被圆所围起来的区域。对于给出的n个点,求出最后一个洞消失的时间;如果没有出现过洞,输出-1。

最后一个洞♂

考虑3个圆的情况,发现洞消失的位置即三个圆心围成的三角形的外心,而且当且仅当三角形是锐角三角形的时候才会存在洞。
要不然就是正方形的中心。、
因为坐标是整数,所以不会出现正五边形以上的,所以情况就这2种。

因此我们可以枚举所有的三角形和正方形,进而枚举所有可能的洞。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 105;
#define FOR(i,j,k) for(int i=j;i<=k;++i)
double sqr(double d) { return d * d; }
bool deql(double a, double b)
{ return fabs(a - b) < 1e-10; }
bool triangle(double a, double b, double c)
{ return a * a + b * b >= c * c; }
bool square(double a, double b, double c)
{ return deql(a * a + b * b, c * c) && deql(a, b); }
struct Point {
    double x, y;
    Point(double a = 0, double b = 0): x(a), y(b) { }
    bool operator== (const Point &b) const {
        return x == b.x && y == b.y;
    }
} pt[N];
double dis(const Point &a, const Point &b) {
    return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
Point *circumcenter(const Point &x, const Point &y, const Point &z) {
    static Point p;
    double A2, B2, A1, B1, C2, C1, d, d1, d2;
    A1 = 2 * (y.x - x.x); B1 = 2 * (y.y - x.y);
    C1 = sqr(y.x) - sqr(x.x) + sqr(y.y) - sqr(x.y);
    A2 = 2 * (z.x - y.x); B2 = 2 * (z.y - y.y);
    C2 = sqr(z.x) - sqr(y.x) + sqr(z.y) - sqr(y.y);
    d  = A1 * B2 - B1 * A2;
    d1 = C1 * B2 - B1 * C2;
    d2 = A1 * C2 - C1 * A2;
    if (d == 0.0) return 0;
    return &(p = Point(d1 / d, d2 / d));
}
int n;
double getmin(Point x) {
    double r = 1e9;
    FOR(i,1,n) r = min(r, dis(pt[i], x));
    return r;
}
int main() {
    Point c, w, *tmp; double ans = -1;
    scanf("%d", &n);
    FOR(i,1,n) scanf("%lf%lf", &pt[i].x, &pt[i].y);
    FOR(i,1,n) FOR(j,i+1,n) FOR(k,j+1,n) {
        Point x = pt[i], y = pt[j], z = pt[k];
        double a = dis(y, z), b = dis(x, y), c = dis(x, z), d;
        if (square(b, c, a)) swap(c, a), swap(x, y);
        if (square(a, c, b)) swap(c, b), swap(y, z);
        if (square(a, b, c)) {
            c = Point((x.x + z.x) / 2, (x.y + z.y) / 2);
            w = Point(c.x * 2 - y.x, c.y * 2 - y.y);
            FOR(l,1,n) if (pt[l] == w) {
                double t = getmin(c);
                if (t * 2 > a && ans < t) ans = t;
                break;
            }
        }
        tmp = circumcenter(x, y, z);
        if (!tmp) continue;
        if (!triangle(a, b, c) || !triangle(a, c, b) || !triangle(b, c, a)) continue;
        double mx = max(a, max(b, c)), t = getmin(*tmp);
        if (t * 2 > mx && ans < t) ans = t;
    }
    if (ans < 0) puts("-1");
    else printf("%.9lf", ans);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值