题意
- 有一块奶酪,高度为h,内部有n个球洞,半径均为r,问这些球洞能否贯穿奶酪
思路
- 使用并查集,合并到顶和底两个大集合中,最后检查顶和底是否在同一个集合
- 注意,和顶部连通的球洞可能同时和底部连通,注意处理方式
- 另一种思路为使用深度优先搜索,看全部搜完后最大深度能否超过h
AC代码(并查集)
#include<bits/stdc++.h>
using namespace std;
typedef struct{
long long x,y,z;
}C;
C a[1010];
int fa[1010];
long long n,h,r;
bool cmp(C x,C y){
return x.z<y.z;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){
fa[find(x)]=find(y);
}
long long dis(int p,int q){
return (a[p].x-a[q].x)*(a[p].x-a[q].x)+(a[p].y-a[q].y)*(a[p].y-a[q].y)+(a[p].z-a[q].z)*(a[p].z-a[q].z);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
//n为底,n+1为顶
scanf("%lld%lld%lld",&n,&h,&r);
for(int i=0;i<n;i++) scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);
for(int i=0;i<=n+1;i++) fa[i]=i;
for(int i=0;i<n;i++){
if(r*r>=a[i].z*a[i].z) {merge(i,n);}
if(r*r>=(a[i].z-h)*(a[i].z-h)){merge(i,n+1);}//注意一个洞可以同时贯通顶部和底部
for(int j=0;j<n;j++){
if(i!=j&&dis(i,j)<=4*r*r){
merge(i, j);
}
}
}
if(find(n)==find(n+1))printf("Yes\n");
else printf("No\n");
}
return 0;
}