题意解释:
有 n 个圈,分别给出坐标(x,y)和半径 r。给两个点的坐标 s(x1,y1)和 t(x2,y2),求是否能至少经过一个圈,让 s 能到 t 点去。
解题思路:
这个可以用并查集来做:
首先,s 可以在有交点的两圆之间移动,所以,有交点的两个圆可以视为一个圆。而 s 和 t 所在的圆可能不止一个,但是由于 n≤3000,所以直接枚举所有 s 和 t 所在的圆就可以。
这样就可以用并查集来做了
用并查集来区分圆,用vector来存 s 和 t 所在的圆的下标。
(一定要用long long ,用double会寄,但是也有玄学用double过的)
代码如下`
#include<bits/stdc++.h>
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define dec(a,b,c) for(int a=b;a>=c;a--)
#define pb push_back
#define x first
#define y second
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define LL long long
#define PII pair<int,int>
#define INf 0x3f3f3f3f;
#define LNF 0x3f3f3f3f3f3f3f3f;
#define PI acos(-1)
using namespace std;
const int N=3e3+10;
int p[N];
vector<int> v1,v2;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
struct Node
{
LL x,y,r;
}a[N];
LL num(LL a,LL b,LL c,LL d)
{
return (a-c)*(a-c)+(b-d)*(b-d);
}
LL num(LL a)
{
return a*a;
}
int main()
{
ios;
int n;
cin>>n;
rep(i,1,n)
p[i]=i;
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
rep(i,1,n)
{
cin>>a[i].x>>a[i].y>>a[i].r;
rep(j,1,i-1)
{
LL k=num(a[i].x,a[i].y,a[j].x,a[j].y);
if(k<=num(a[i].r+a[j].r)&&k>=num(a[i].r-a[j].r))
{
p[find(j)]=find(i);
}
}
if(num(a[i].x,a[i].y,x1,y1)==num(a[i].r))
v1.pb(i);
if(num(a[i].x,a[i].y,x2,y2)==num(a[i].r))
v2.pb(i);
}
for(auto i:v1)
{
for(auto j:v2)
if(find(i)==find(j))
{
cout<<"Yes"<<endl;
return 0;
}
}
cout<<"No"<<endl;
return 0;
}