AtCoder Beginner Contest 259 - D - Circumferences - 题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 259 - D - Circumferences - 题解相关的知识,希望对你有一定的参考价值。

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 400400400 points

Problem Statement

You are given NNN circles on the xyxyxy-coordinate plane. For each i=1,2,…,Ni = 1, 2, \\ldots, Ni=1,2,,N, the iii-th circle is centered at (xi,yi)(x_i, y_i)(xi,yi) and has a radius of rir_iri.

Determine whether it is possible to get from (sx,sy)(s_x, s_y)(sx,sy) to (tx,ty)(t_x, t_y)(tx,ty) by only passing through points that lie on the circumference of at least one of the NNN circles.

Constraints

  • 1≤N≤30001 \\leq N \\leq 30001N3000
  • −109≤xi,yi≤109-10^9 \\leq x_i, y_i \\leq 10^9109xi,yi109
  • 1≤ri≤1091 \\leq r_i \\leq 10^91ri109
  • (sx,sy)(s_x, s_y)(sx,sy) lies on the circumference of at least one of the NNN circles.
  • (tx,ty)(t_x, t_y)(tx,ty) lies on the circumference of at least one of the NNN circles.
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

NNN
sxs_xsx sys_ysy txt_xtx tyt_yty
x1x_1x1 y1y_1y1 r1r_1r1
x2x_2x2 y2y_2y2 r2r_2r2
⋮\\vdots
xNx_NxN yNy_NyN rNr_NrN

Output

If it is possible to get from (sx,sy)(s_x, s_y)(sx,sy) to (tx,ty)(t_x, t_y)(tx,ty), print Yes; otherwise, print No. Note that the judge is case-sensitive.


Sample Input 1

4
0 -2 3 3
0 0 2
2 0 2
2 3 1
-3 3 3

Sample Output 1

Yes

Here is one way to get from (0,−2)(0, -2)(0,2) to (3,3)(3, 3)(3,3).

  • From (0,−2)(0, -2)(0,2), pass through the circumference of the 111-st circle counterclockwise to reach (1,−3)(1, -\\sqrt3)(1,3 ).
  • From (1,−3)(1, -\\sqrt3)(1,3 ), pass through the circumference of the 222-nd circle clockwise to reach (2,2)(2, 2)(2,2).
  • From (2,2)(2, 2)(2,2), pass through the circumference of the 333-rd circle counterclockwise to reach (3,3)(3, 3)(3,3).

Thus, Yes should be printed.


Sample Input 2

3
0 1 0 3
0 0 1
0 0 2
0 0 3

Sample Output 2

No

It is impossible to get from (0,1)(0, 1)(0,1) to (0,3)(0, 3)(0,3) by only passing through points on the circumference of at least one of the circles, so No should be printed.

题目大意

给你一些圆⚪,以及两个点📍

问你 在只经过圆周⚪的前提下,能否由第一个点📍达到第二个点📍

数据保证两个点都在圆周⚪上

解题思路

本题圆⚪的数量级别为 3000 3000 3000 O ( n 2 ) O(n^2) O(n2)的复杂度在AtCoder上2秒可以通过。

所以不难想到,我们可以把此题转换为连通图问题

把一个圆⚪看成一个节点,相交的两个圆⚪之间存在一条路径

很容易在 O ( n 2 ) O(n^2) O(n2)的时间内把图构建出来

然后,只需要看两个点📍所在的节点(如果某个点在多个圆⚪上,任取一个作为这个点📍所在的节点即可)是否在一个连通图上

定义圆⚪的数据结构

struct circle 
    ll x, y, r;
    bool used = false;  // 后面在判断连通图的时候会用到
;

判断两个圆⚪是否相交/相切

相交/相切 条件: R − r ≤ 圆 心 距 离 ≤ R + r R-r \\leq 圆心距离 \\leq R+r RrR+r

严格地说“相切”不属于“相交”。这里感谢@ZZXzzx0_0大佬的指正~

inline bool intersect(int x, int y) 
    ll r = a[x].r;
    ll R = a[y].r;
    if (r > R)
        swap(r, R);
    ll distance2 = (a[x].x - a[y].x) * (a[x].x - a[y].x) + (a[x].y - a[y].y) * (a[x].y - a[y].y);
    return (R - r) * (R - r) <= distance2 && distance2 <= (R + r) * (R + r);

判断一个点📍是否在一个圆⚪上

// (x, y) 是否在第th个圆⚪上
inline bool onCircle(ll x, ll y, int th) 
    return (x - a[th].x) * (x - a[th].x) + (y - a[th].y) * (y - a[th].y) == a[th].r * a[th].r;

是否能从节点x走到节点y

建好图后,假设两个点📍分别在节点 x x x和节点 y y y上,则只需要判断 x x x y y y是否在一个连通图上即可

bool ifCanGo(int x, int y) 
    // 把从x能到达的所有节点的used标记为true
    queue<int> canGo;
    canGo.push(x);
    a[x].used = true;
    while (canGo.size()) 
        int thisNode = canGo.front();
        canGo.pop();
        for (int &t : ma[thisNode]) 
            if (!a[t].used) 
                canGo.push(t);
                a[t].used = true;
            
        
    
    // 判断y是否被标记了
    return a[y].used;

建图

vector<int> ma[3010];  // 存图

for (int i = 0; i < n; i++) 
    for (int j = i + 1; j < n; j++) 
        if (intersect(i, j)) 
            ma[i].push_back(j);
            ma[j].push_back(i);
        
    


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

// 小心精度误差

// #define Yes puts("Yes"); return 0;
// #define No puts("No"); return 0;

#define EXIT(x) puts(#x); return 0;
#define Yes
#define No

struct circle 
    ll x, y, r;
    bool used = false;  
;

circle a[3010];

inline bool onCircle(ll x, ll y, int th) 
    return (x - a[th].x) * (x - a[th].x) + (y - a[th].y) * (y - a[th].y) == a[th].r * a[th].r;


inline bool intersect(int x, int y) 
    ll r = a[x].r;
    ll R = a[y].r;
    if (r > R)
        swap(r, R);
    ll distance2 = (a[x].x - a[y].x) * (a[x].x - a[y].x) + (a[x].y - a[y].y) * (a[x].y - a[y].y);
    return (R - r) * (R - r) <= distance2 && distance2 <= (R + r) * (R + r);


vector<int> ma[3010];  // 图

bool ifCanGo(int x, int y) 
    queue<int> canGo;
    canGo.push(x);
    a[x].used = true;
    while (canGo.size()) 
        int thisNode = canGo.front();
        canGo.pop();
        for<

以上是关于AtCoder Beginner Contest 259 - D - Circumferences - 题解的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242