2024 (ICPC) Jiangxi Provincial Contest I 题 Neuvillette Circling题解

简单思路

一个圆套中了几个点,如果不断缩小这个圆,那么最终的结果有两种

  1. 有两个点卡住了这个圆,且这两点一定是直径
  2. 有三个或者三个以上的点卡住了这个圆,圆心在这三个点围成的三角形的外接圆圆心。

因此我们枚举两点作为直径,或者枚举三个点作为圆的内接三角形,求这个三角形的外接圆圆心即可。

最后对这些圆进行判断一共围住了几个点。

复杂度大概\(O(n^3+n^4)\)

参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define endl '\n'
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define rep(i, a, b) for (int i = (a); i < (b); ++i)
#define Forget_that return
#define f(x, y) (x * x + y * y)
#define Just_go 0
#define Endl endl
#define ednl endl
#define eldn endl
#define dnel endl
#define enndl endl
#define Ednl endl
#define Edml endl
#define llmax 9223372036854775807
#define intmax 2147483647
#define f(x, y) (x * x + y * y)

struct point
{
    ld x;
    ld y;
    point(ld xx = 0, ld yy = 0)
    {
        x = xx;
        y = yy;
    }

} arr[100000];

point fun(const point &p1, const point &p2, const point &p3)  //求三角形外接圆圆心
{
    ld x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y, x3 = p3.x, y3 = p3.y;
    ld d1 = f(x2, y2) - f(x1, y1), d2 = f(x3, y3) - f(x2, y2);
    ld fm = 2 * ((y3 - y2) * (x2 - x1) - (y2 - y1) * (x3 - x2));
    ld ans_x = ((y3 - y2) * d1 - (y2 - y1) * d2) / fm;
    ld ans_y = ((x2 - x1) * d2 - (x3 - x2) * d1) / fm;
    return point(ans_x, ans_y);
}

struct circle
{
    ld x;
    ld y;
    ld r;
    int cnt;
    circle(ld xx, ld yy, ld rr)
    {
        x = xx;
        y = yy;
        r = rr;
        cnt = 0;
    }
};

ld dis(const point &a, const point &b)
{
    return sqrtl(1.0L * (a.x - b.x) * (a.x - b.x) + 1.0L * (a.y - b.y) * (a.y - b.y));
}

ld dis(const circle &a, const point &b)
{
    return sqrtl(1.0L * (a.x - b.x) * (a.x - b.x) + 1.0L * (a.y - b.y) * (a.y - b.y));
}

bool isIn(const circle &x, const point &b)
{
    ld dist = dis(x, b);
    if (dist < x.r)
        return true;
    if (abs(dist - x.r) < 1e-7)
        return true;
    return false;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n;

    cin >> n;
    _rep(i, 1, n)
    {
        ll xtemp;
        ll ytemp;
        cin >> xtemp >> ytemp;
        arr[i].x = xtemp;
        arr[i].y = ytemp;
    }
    vector<circle> vec;

    for (int i = 1; i <= n; i++)      //枚举直径,构造圆
    {
        for (int j = i + 1; j <= n; j++)
        {
            vec.push_back(circle(0.5L * (arr[i].x + arr[j].x), 0.5L * (arr[i].y + arr[j].y), 0.5L * dis(arr[i], arr[j])));
        }
    }

    for (int i = 1; i <= n; i++)   //枚举三角形,求外接圆
    {
        for (int j = i + 1; j <= n; j++)
        {
            for (int k = j + 1; k <= n; k++)
            {
                point temp = fun(arr[i], arr[j], arr[k]);   //外接圆圆心
                vec.push_back(circle(temp.x, temp.y, dis(temp, arr[i])));
            }
        }
    }

    for (auto it = vec.begin(); it != vec.end(); it++)
    {
        for (int i = 1; i <= n; i++)
        {
            if (isIn(*it, arr[i]))    //判断圆中包含多少个点
                it->cnt++;
        }
    }

    vector<ld> ans(n + 10, 1e14);

    for (auto it = vec.begin(); it != vec.end(); it++)  //写题解的时候发现这里应该判断一下,因为有可能不存在圆能恰好围住x个点,但是存在圆能恰好围住x+1个点。建议加强数据,也有可能我写题解的时候想多了。
        ans[it->cnt] = min(it->r, ans[it->cnt]);

    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j < i; j++)
        {
            cout << fixed << setprecision(10) << ans[i] << endl;
        }
    }

    Forget_that Just_go;
}

posted @ 2025-01-20 23:40  AcidBarium  阅读(72)  评论(0)    收藏  举报