传送门
分析:
这个题运用并查集,先找出连接顶面的球和连接底面的球,再把所有的球能连接的全部合并,最后枚举所有连接顶面和底面的球,如果有联通的,就说明Jerry能从底走到顶
需要注意的就是求距离时函数要用 $ double $ 定义,否则精度问题比你卡的死死地 。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define re register
using namespace std ;
const int maxn = 10005 ;
inline int read () {
int f = 1 , x = 0 ;
char ch = getchar () ;
while(ch > '9' || ch < '0') {if(ch == '-') f = -1 ; ch = getchar () ;}
while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0' ; ch = getchar () ;}
return x * f ;
}
int T , n , h ;
long long x[maxn] , y[maxn] , z[maxn] ;
long long dis[maxn] , r ;
int f[maxn] , f1[maxn] , f2[maxn] ;
//f1[]与顶面相连的球的父亲,与底面相连的球的父亲
int top , bot , flag ;
//top是与顶面相连的球的数量 , bot是与低面相连的
inline double Dis(long long x , long long xx , long long y , long long yy , long long z , long long zz) {
return sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy) + (z - zz) * (z - zz)) ;
}
inline int find(int x) {
if(x != f[x]) f[x] = find(f[x]) ;
return f[x] ;
}
inline void unionn(int x , int y) {
int f1 = find(x) , f2 = find(y) ;
if(f1 != f2)
f[f1] = f2 ;
}
int main () {
// freopen("cheese.in" , "r" , stdin) ;
T = read () ;
while(T--) {
n = read () ; h = read () ;
scanf("%lld" , &r) ;
top = 0 ; bot = 0 ; flag = 0 ;
for(re int i = 1 ; i <= n ; ++ i)
f[i] = i ;
for(re int i = 1 ; i <= n ; ++ i) {
scanf("%lld%lld%lld" , &x[i] , &y[i] , &z[i]) ;
if(z[i] + r >= h) f1[++ top] = i ;
if(z[i] - r <= 0) f2[++ bot] = i ;
for(re int j = 1 ; j <= i ; ++ j)
if(Dis(x[i] , x[j] , y[i] , y[j] , z[i] , z[j]) <= 2 * r) {
unionn(i , j) ;
}
}
for(re int i = 1 ; i <= top ; ++ i)
for(re int j = 1 ; j <= bot; ++ j)
if(find(f1[i]) == find(f2[j])) {
flag = 1 ;
break ;
}
if (flag == 1) printf( "Yes
" );
else printf( "No
" );
}
return 0;
}