AtCoder Beginner Contest 259 D - Circumferences(并查集)

l i n k link link

题意

给你一些圆,再给出两个点,两个点均为圆上,你可以走在圆上的任意位置,问这两个点是否联通?

思路

这个题和今年蓝桥杯省赛的一道题扫雷背景很像,但是做法不同。

根据题目,我们其实能理解一个事情:只要两个圆相交或相切,代表着两个圆互通。

如果另外有一个圆和这两个圆的任意一个圆有交集,那么这三个圆互通。

那么我们就可以想到使用并查集维护这一个性质,如果两个圆相交就使用并查集合并。

现在问题转化成了:如何判断两个圆相交?

设两个圆的圆心距为 p p p,半径分别是 R , r R,r R,r

相交: R − r < p < P + r R-rRr<p<P+r

外切: p = R + r p=R+r p=R+r

内切: p = R − r p=R-r p=Rr

也就是只要满足 R − r ≤ p ≤ R + r R-r\le p\le R+r RrpR+r即可合并。

#include 
using namespace std;
#define int long long
struct node
{
    int x, y, r;
} s[210210];
bool ok(int x, int y, int xx, int yy, int r)
{
    if ((x - xx) * (x - xx) + (y - yy) * (y - yy) == r * r)
        return 1;
    return 0;
}
bool ok2(int x, int y, int r2, int xx, int yy, int r)
{
    if ((x - xx) * (x - xx) + (y - yy) * (y - yy) <= (r + r2) * (r + r2) && (r - r2) * (r - r2) <= (x - xx) * (x - xx) + (y - yy) * (y - yy))
        return 1;
    return 0;
}
vector<int> ans1;
vector<int> ans2;
int a[2102100];
int find(int x)
{
    if (a[x] != x)
        a[x] = find(a[x]);
    return a[x];
}
signed main()
{
    int n;
    cin >> n;
    int sx, sy, tx, ty;
    cin >> sx >> sy >> tx >> ty;
    for (int i = 1; i <= n; i++)
    {
        a[i] = i;
        cin >> s[i].x >> s[i].y >> s[i].r;
        if (ok(sx, sy, s[i].x, s[i].y, s[i].r))
            ans1.push_back(i);
        if (ok(tx, ty, s[i].x, s[i].y, s[i].r))
            ans2.push_back(i);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (ok2(s[i].x, s[i].y, s[i].r, s[j].x, s[j].y, s[j].r))
                a[find(i)] = find(j);
        }
    }
    for (int i = 0; i < ans1.size(); i++)
    {
        for (int j = 0; j < ans2.size(); j++)
        {
            if (find(ans1[i]) == find(ans2[j]))
            {
                cout << "Yes" << endl;
                return 0;
            }
        }
    }
    cout << "No" << endl;
}

你可能感兴趣的:(算法题解分类,#,数据结构,蓝桥杯,算法,职场和发展)