题目传送门
这题很明显可以用并查集,把所有相交的球体都合并成为一条通路,最后枚举判断
#include <bits/stdc++.h>
#define MAX 1005
#define ll long long
using namespace std;
/***并查集***/
int par[MAX];
int find(int x){
if(par[x] == x)
return x;
par[x] = find(par[x]);
return par[x];
}
bool isConnected(int x, int y){
return find(x) == find(y);
}
void connect(int x, int y){
int a = find(x);
int b = find(y);
if(a == b) {
return;
}
par[a] = b;
}
/*并查集结束*/
int n;
ll h,r;
struct Pos {
ll x, y, z;
} a[MAX];
ll sqr(ll x){ //平方
return x*x;
}
bool check(Pos p1, Pos p2){ //判断两个球体是否相交或相切
ll dist = sqr(p1.x-p2.x) + sqr(p1.y-p2.y) + sqr(p1.z-p2.z);
//为防止精度损失,采用平方比较
if(dist <= 4*r*r) { //球心距小于等于半径和,则两圆相切或相交
return true; //4*r*r = (2r)^2, 即两球半径和的平方
}
return false;
}
void solve(){
cin >> n >> h >> r;
for(int i = 1; i <= n; i++) {
par[i] = i;
}
for (int i = 1; i <= n; i++) {
scanf("%lld %lld %lld", &a[i].x, &a[i].y, &a[i].z);
}
for (int i = 1; i <= n-1; i++) {
for (int j = i+1; j <= n; j++) {
if(check(a[i], a[j])) {
connect(i,j);
}
}
}
vector<int> v1; //在底部的球
vector<int> v2; //在顶部的球
for (int i = 1; i <= n; i++) {
if(a[i].z - r <= 0) //如果在底部
v1.push_back(i);
if(a[i].z + r >= h) //如果在顶部
v2.push_back(i);
}
int flag = false;
for (int i = 0; i < (int)v1.size(); i++) {
for (int j = 0; j < (int)v2.size(); j++) {
if(isConnected(v1[i], v2[j])) { //如果从底面到顶面有通路
cout << "Yes" << endl;
flag = true;
break;
}
}
if(flag) {
break;
}
}
if(!flag)
cout << "No" << endl;
}
int main()
{
int t;
cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
return 0;
}